Ghost/core/server/api/v2/subscribers.js
Naz Gargol 48d6e7298a
Refactored content-disposition header handling in API v2 (#10374)
closes https://github.com/TryGhost/Ghost/issues/10331

- Left only a filename part to be handled by controller configuration, the rest was extracted to more generic headers layer
2019-01-14 18:05:16 +00:00

220 lines
6.6 KiB
JavaScript

const fs = require('fs-extra');
const Promise = require('bluebird');
const models = require('../../models');
const fsLib = require('../../lib/fs');
const common = require('../../lib/common');
const subscribers = {
docName: 'subscribers',
browse: {
options: [
'limit',
'fields',
'filter',
'order',
'debug',
'page'
],
permissions: true,
validation: {},
query(frame) {
return models.Subscriber.findPage(frame.options);
}
},
read: {
headers: {},
data: [
'id',
'email'
],
validation: {},
permissions: true,
query(frame) {
return models.Subscriber.findOne(frame.data);
}
},
add: {
statusCode: 201,
headers: {},
validation: {
data: {
email: {required: true}
}
},
permissions: true,
query(frame) {
return models.Subscriber.getByEmail(frame.data.subscribers[0].email)
.then((subscriber) => {
if (subscriber && frame.options.context.external) {
// we don't expose this information
return Promise.resolve(subscriber);
} else if (subscriber) {
return Promise.reject(new common.errors.ValidationError({message: common.i18n.t('errors.api.subscribers.subscriberAlreadyExists')}));
}
return models.Subscriber
.add(frame.data.subscribers[0])
.catch((error) => {
if (error.code && error.message.toLowerCase().indexOf('unique') !== -1) {
return Promise.reject(new common.errors.ValidationError({message: common.i18n.t('errors.api.subscribers.subscriberAlreadyExists')}));
}
return Promise.reject(error);
});
});
}
},
edit: {
headers: {},
options: [
'id'
],
validation: {
id: {
required: true
}
},
permissions: true,
query(frame) {
return models.Subscriber.edit(frame.data.subscribers[0], frame.options)
.then((model) => {
if (!model) {
return Promise.reject(new common.errors.NotFoundError({
message: common.i18n.t('errors.api.subscribers.subscriberNotFound')
}));
}
return model;
});
}
},
destroy: {
statusCode: 204,
headers: {
cacheInvalidate: true
},
options: [
'id',
'email'
],
validation: {},
permissions: true,
query(frame) {
/**
* ### Delete Subscriber
* If we have an email param, check the subscriber exists
* @type {[type]}
*/
function getSubscriberByEmail(options) {
if (options.email) {
return models.Subscriber.getByEmail(options.email, options)
.then((subscriber) => {
if (!subscriber) {
return Promise.reject(new common.errors.NotFoundError({
message: common.i18n.t('errors.api.subscribers.subscriberNotFound')
}));
}
options.id = subscriber.get('id');
return options;
});
}
return Promise.resolve(options);
}
return getSubscriberByEmail(frame.options)
.then((options) => {
return models.Subscriber
.destroy(options)
.return(null);
});
}
},
exportCSV: {
headers: {
disposition: {
type: 'csv',
value() {
const datetime = (new Date()).toJSON().substring(0, 10);
return `subscribers.${datetime}.csv`;
}
}
},
response: {
format: 'plain'
},
permissions: {
method: 'browse'
},
validation: {},
query(frame) {
return models.Subscriber.findAll(frame.options)
.catch((err) => {
return Promise.reject(new common.errors.GhostError({err: err}));
});
}
},
importCSV: {
statusCode: 201,
permissions: {
method: 'add'
},
validation: {},
query(frame) {
let filePath = frame.file.path,
fulfilled = 0,
invalid = 0,
duplicates = 0;
return fsLib.readCSV({
path: filePath,
columnsToExtract: [{name: 'email', lookup: /email/i}]
}).then((result) => {
return Promise.all(result.map((entry) => {
const apiv2 = require('./index');
return apiv2.subscribers.add.query({
data: {subscribers: [{email: entry.email}]},
options: {
context: frame.options.context
}
}).reflect();
})).each((inspection) => {
if (inspection.isFulfilled()) {
fulfilled = fulfilled + 1;
} else {
if (inspection.reason() instanceof common.errors.ValidationError) {
duplicates = duplicates + 1;
} else {
invalid = invalid + 1;
}
}
});
}).then(() => {
return {
meta: {
stats: {
imported: fulfilled,
duplicates: duplicates,
invalid: invalid
}
}
};
}).finally(() => {
// Remove uploaded file from tmp location
return fs.unlink(filePath);
});
}
}
};
module.exports = subscribers;