mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added GET/DELETE /subscribers/email/:email/ endpoints (#9238)
no issue - useful for managing subscribers via external systems/API calls where it's likely only the e-mail address will be known - adds `GET /subscribers/email/:email/` - adds `DELETE /subscribers/email/:email/`
This commit is contained in:
parent
0d54326121
commit
bcc98e5536
4 changed files with 69 additions and 6 deletions
|
@ -84,9 +84,11 @@ module.exports = function apiRoutes() {
|
||||||
api.http(api.subscribers.importCSV)
|
api.http(api.subscribers.importCSV)
|
||||||
);
|
);
|
||||||
apiRouter.get('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.read));
|
apiRouter.get('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.read));
|
||||||
|
apiRouter.get('/subscribers/email/:email', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.read));
|
||||||
apiRouter.post('/subscribers', labs.subscribers, mw.authenticatePublic, api.http(api.subscribers.add));
|
apiRouter.post('/subscribers', labs.subscribers, mw.authenticatePublic, api.http(api.subscribers.add));
|
||||||
apiRouter.put('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.edit));
|
apiRouter.put('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.edit));
|
||||||
apiRouter.del('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.destroy));
|
apiRouter.del('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.destroy));
|
||||||
|
apiRouter.del('/subscribers/email/:email', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.destroy));
|
||||||
|
|
||||||
// ## Roles
|
// ## Roles
|
||||||
apiRouter.get('/roles/', mw.authenticatePrivate, api.http(api.roles.browse));
|
apiRouter.get('/roles/', mw.authenticatePrivate, api.http(api.roles.browse));
|
||||||
|
|
|
@ -53,7 +53,7 @@ subscribers = {
|
||||||
* @return {Promise<Subscriber>} Subscriber
|
* @return {Promise<Subscriber>} Subscriber
|
||||||
*/
|
*/
|
||||||
read: function read(options) {
|
read: function read(options) {
|
||||||
var attrs = ['id'],
|
var attrs = ['id', 'email'],
|
||||||
tasks;
|
tasks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,6 +190,29 @@ subscribers = {
|
||||||
destroy: function destroy(options) {
|
destroy: function destroy(options) {
|
||||||
var tasks;
|
var tasks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ### 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(function (subscriber) {
|
||||||
|
if (!subscriber) {
|
||||||
|
return Promise.reject(new errors.NotFoundError({
|
||||||
|
message: i18n.t('errors.api.subscribers.subscriberNotFound')
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
options.id = subscriber.get('id');
|
||||||
|
return options;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ### Delete Subscriber
|
* ### Delete Subscriber
|
||||||
* Make the call to the Model layer
|
* Make the call to the Model layer
|
||||||
|
@ -201,8 +224,9 @@ subscribers = {
|
||||||
|
|
||||||
// Push all of our tasks into a `tasks` array in the correct order
|
// Push all of our tasks into a `tasks` array in the correct order
|
||||||
tasks = [
|
tasks = [
|
||||||
apiUtils.validate(docName, {opts: apiUtils.idDefaultOptions}),
|
apiUtils.validate(docName, {opts: ['id', 'email']}),
|
||||||
apiUtils.handlePermissions(docName, 'destroy'),
|
apiUtils.handlePermissions(docName, 'destroy'),
|
||||||
|
getSubscriberByEmail,
|
||||||
doQuery
|
doQuery
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,8 @@ utils = {
|
||||||
to: {isDate: true},
|
to: {isDate: true},
|
||||||
fields: {matches: /^[\w, ]+$/},
|
fields: {matches: /^[\w, ]+$/},
|
||||||
order: {matches: /^[a-z0-9_,\. ]+$/i},
|
order: {matches: /^[a-z0-9_,\. ]+$/i},
|
||||||
name: {}
|
name: {},
|
||||||
|
email: {isEmail: true}
|
||||||
},
|
},
|
||||||
// these values are sanitised/validated separately
|
// these values are sanitised/validated separately
|
||||||
noValidation = ['data', 'context', 'include', 'filter', 'forUpdate', 'transacting', 'formats'],
|
noValidation = ['data', 'context', 'include', 'filter', 'forUpdate', 'transacting', 'formats'],
|
||||||
|
|
|
@ -155,10 +155,10 @@ describe('Subscribers API', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Destroy', function () {
|
describe('Destroy', function () {
|
||||||
var firstSubscriber = testUtils.DataGenerator.Content.subscribers[0].id;
|
var firstSubscriber = testUtils.DataGenerator.Content.subscribers[0];
|
||||||
|
|
||||||
it('can destroy subscriber as admin', function (done) {
|
it('can destroy subscriber as admin', function (done) {
|
||||||
SubscribersAPI.destroy(_.extend({}, testUtils.context.admin, {id: firstSubscriber}))
|
SubscribersAPI.destroy(_.extend({}, testUtils.context.admin, {id: firstSubscriber.id}))
|
||||||
.then(function (results) {
|
.then(function (results) {
|
||||||
should.not.exist(results);
|
should.not.exist(results);
|
||||||
|
|
||||||
|
@ -166,8 +166,28 @@ describe('Subscribers API', function () {
|
||||||
}).catch(done);
|
}).catch(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can destroy subscriber by email', function (done) {
|
||||||
|
SubscribersAPI.destroy(_.extend({}, testUtils.context.admin, {email: firstSubscriber.email}))
|
||||||
|
.then(function (results) {
|
||||||
|
should.not.exist(results);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns NotFoundError for unknown email', function (done) {
|
||||||
|
SubscribersAPI.destroy(_.extend({}, testUtils.context.admin, {email: 'unknown@example.com'}))
|
||||||
|
.then(function (results) {
|
||||||
|
done(new Error('Destroy subscriber should not be possible with unknown email.'));
|
||||||
|
}, function (err) {
|
||||||
|
should.exist(err);
|
||||||
|
(err instanceof errors.NotFoundError).should.eql(true);
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
it('CANNOT destroy subscriber', function (done) {
|
it('CANNOT destroy subscriber', function (done) {
|
||||||
SubscribersAPI.destroy(_.extend({}, testUtils.context.editor, {id: firstSubscriber}))
|
SubscribersAPI.destroy(_.extend({}, testUtils.context.editor, {id: firstSubscriber.id}))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
done(new Error('Destroy subscriber should not be possible as editor.'));
|
done(new Error('Destroy subscriber should not be possible as editor.'));
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
|
@ -227,6 +247,22 @@ describe('Subscribers API', function () {
|
||||||
}).catch(done);
|
}).catch(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('with email', function (done) {
|
||||||
|
SubscribersAPI.browse({context: {user: 1}}).then(function (results) {
|
||||||
|
should.exist(results);
|
||||||
|
should.exist(results.subscribers);
|
||||||
|
results.subscribers.length.should.be.above(0);
|
||||||
|
|
||||||
|
var firstSubscriber = _.find(results.subscribers, {id: testUtils.DataGenerator.Content.subscribers[0].id});
|
||||||
|
return SubscribersAPI.read({context: {user: 1}, email: firstSubscriber.email});
|
||||||
|
}).then(function (found) {
|
||||||
|
should.exist(found);
|
||||||
|
testUtils.API.checkResponse(found.subscribers[0], 'subscriber');
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
it('CANNOT fetch a subscriber which doesn\'t exist', function (done) {
|
it('CANNOT fetch a subscriber which doesn\'t exist', function (done) {
|
||||||
SubscribersAPI.read({context: {user: 1}, id: 999}).then(function () {
|
SubscribersAPI.read({context: {user: 1}, id: 999}).then(function () {
|
||||||
done(new Error('Should not return a result'));
|
done(new Error('Should not return a result'));
|
||||||
|
|
Loading…
Add table
Reference in a new issue