diff --git a/ghost/members-api/lib/repositories/member.js b/ghost/members-api/lib/repositories/member.js index e4e349603f..0d03c7fb97 100644 --- a/ghost/members-api/lib/repositories/member.js +++ b/ghost/members-api/lib/repositories/member.js @@ -1,6 +1,7 @@ const _ = require('lodash'); const errors = require('@tryghost/errors'); const tpl = require('@tryghost/tpl'); +const ObjectId = require('bson-objectid'); const messages = { noStripeConnection: 'Cannot {action} without a Stripe Connection', @@ -334,6 +335,79 @@ module.exports = class MemberRepository { return bulkDestroyResult; } + async bulkEdit(data, options) { + const {all, filter, search} = options; + + if (!['unsubscribe', 'addLabel', 'removeLabel'].includes(data.action)) { + throw new errors.IncorrectUsageError({ + message: 'Unsupported bulk action' + }); + } + + if (!filter && !search && (!all || all !== true)) { + throw new errors.IncorrectUsageError({ + message: tpl(messages.bulkActionRequiresFilter, {action: 'bulk edit'}) + }); + } + + const filterOptions = {}; + + if (options.transacting) { + filterOptions.transacting = options.transacting; + } + + if (options.context) { + filterOptions.context = options.context; + } + + if (all !== true) { + if (filter) { + filterOptions.filter = filter; + } + + if (search) { + filterOptions.search = search; + } + } + + const memberRows = await this._Member.getFilteredCollectionQuery(filterOptions) + .select('members.id') + .distinct(); + + const memberIds = memberRows.map(row => row.id); + + if (data.action === 'unsubscribe') { + return await this._Member.bulkEdit(memberIds, 'members', { + data: { + subscribed: false + } + }); + } + + if (data.action === 'removeLabel') { + const membersLabelsRows = await this._Member.getLabelRelations({ + labelId: data.meta.label.id, + memberIds + }); + + const membersLabelsIds = membersLabelsRows.map(row => row.id); + + return this._Member.bulkDestroy(membersLabelsIds, 'members_labels'); + } + + if (data.action === 'addLabel') { + const relations = memberIds.map((id) => { + return { + member_id: id, + label_id: data.meta.label.id, + id: ObjectId() + }; + }); + + return this._Member.bulkAdd(relations, 'members_labels'); + } + } + async upsertCustomer(data) { return await this._StripeCustomer.upsert({ customer_id: data.customer_id, diff --git a/ghost/members-api/package.json b/ghost/members-api/package.json index 4a3a1f2dea..c93746ac98 100644 --- a/ghost/members-api/package.json +++ b/ghost/members-api/package.json @@ -33,6 +33,7 @@ "@types/jsonwebtoken": "^8.5.1", "bluebird": "^3.5.4", "body-parser": "^1.19.0", + "bson-objectid": "^2.0.1", "cookies": "^0.8.0", "express": "^4.16.4", "got": "^9.6.0",