mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
refs https://github.com/TryGhost/Team/issues/1561 With multiple newsletters, unsubscribe links will also need to have a unique reference to the newsletter that the email is for, so that we can unsubscribe members from the particular newsletter automatically when they click on the link. As our existing pattern for members is to use UUID as the external unique reference, this change adds UUID to newsletter schema and populates the existing newsletters with a UUID value. - adds new `uuid` column to newsletter schema - updates newsletter model to add default uuid - updates default newsletter migration to add `uuid` - drops nullable on `uuid` column later in migrations once we have populated existing newsletters
112 lines
3.2 KiB
JavaScript
112 lines
3.2 KiB
JavaScript
const ghostBookshelf = require('./base');
|
|
const ObjectID = require('bson-objectid');
|
|
const uuid = require('uuid');
|
|
|
|
const Newsletter = ghostBookshelf.Model.extend({
|
|
tableName: 'newsletters',
|
|
|
|
defaults: {
|
|
uuid: uuid.v4(),
|
|
sender_reply_to: 'newsletter',
|
|
status: 'active',
|
|
visibility: 'members',
|
|
subscribe_on_signup: true,
|
|
sort_order: 0,
|
|
title_font_category: 'sans_serif',
|
|
title_alignment: 'center',
|
|
show_feature_image: true,
|
|
body_font_category: 'sans_serif',
|
|
show_badge: true,
|
|
show_header_icon: true,
|
|
show_header_title: true,
|
|
show_header_name: true
|
|
},
|
|
|
|
members() {
|
|
return this.belongsToMany('Member', 'members_newsletters', 'newsletter_id', 'member_id')
|
|
.query((qb) => {
|
|
// avoids bookshelf adding a `DISTINCT` to the query
|
|
// we know the result set will already be unique and DISTINCT hurts query performance
|
|
qb.columns('members.*');
|
|
});
|
|
},
|
|
|
|
posts() {
|
|
return this.hasMany('Post');
|
|
},
|
|
|
|
async onSaving(model, _attr, options) {
|
|
ghostBookshelf.Model.prototype.onSaving.apply(this, arguments);
|
|
|
|
if (model.get('name')) {
|
|
model.set('name', model.get('name').trim());
|
|
}
|
|
|
|
if (model.hasChanged('slug') || !model.get('slug')) {
|
|
const slug = model.get('slug') || model.get('name');
|
|
|
|
if (slug) {
|
|
const cleanSlug = await ghostBookshelf.Model.generateSlug(Newsletter, slug, {
|
|
transacting: options.transacting
|
|
});
|
|
|
|
model.set({slug: cleanSlug});
|
|
}
|
|
}
|
|
},
|
|
|
|
subscribeMembersById(memberIds, unfilteredOptions = {}) {
|
|
let pivotRows = [];
|
|
for (const memberId of memberIds) {
|
|
pivotRows.push({
|
|
id: ObjectID().toHexString(),
|
|
member_id: memberId.id,
|
|
newsletter_id: this.id
|
|
});
|
|
}
|
|
|
|
const query = ghostBookshelf.knex.batchInsert('members_newsletters', pivotRows);
|
|
|
|
if (unfilteredOptions.transacting) {
|
|
query.transacting(unfilteredOptions.transacting);
|
|
}
|
|
|
|
return query;
|
|
}
|
|
}, {
|
|
orderDefaultRaw: function () {
|
|
return 'sort_order ASC, created_at ASC, id ASC';
|
|
},
|
|
|
|
orderDefaultOptions: function orderDefaultOptions() {
|
|
return {
|
|
sort_order: 'ASC',
|
|
created_at: 'ASC',
|
|
id: 'ASC'
|
|
};
|
|
},
|
|
|
|
getNextAvailableSortOrder: async function getNextAvailableSortOrder(unfilteredOptions = {}) {
|
|
const options = {
|
|
filter: 'status:active',
|
|
order: 'sort_order DESC', // there's no NQL syntax available here
|
|
limit: 1,
|
|
columns: ['sort_order']
|
|
};
|
|
|
|
if (unfilteredOptions.transacting) {
|
|
options.transacting = unfilteredOptions.transacting;
|
|
}
|
|
|
|
const lastNewsletter = await this.findPage(options);
|
|
|
|
if (lastNewsletter.data.length > 0) {
|
|
return lastNewsletter.data[0].get('sort_order') + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
module.exports = {
|
|
Newsletter: ghostBookshelf.model('Newsletter', Newsletter)
|
|
};
|