mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
✨ Added ability to send newsletter and not publish the post
refs https://github.com/TryGhost/Team/issues/949 - When post is marked as "email-only" we can send it out to the selected audience when publishing without making the post publicly available - The feature is available for experimentation behind "email only" alpha flag available in labs
This commit is contained in:
parent
a7503b9c0f
commit
3c822e0457
3 changed files with 59 additions and 9 deletions
|
@ -651,6 +651,12 @@ Post = ghostBookshelf.Model.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: this is a stopgap solution for email-only posts where their status is unchanged after publish
|
||||||
|
// but the usual publis/send newsletter flow continues
|
||||||
|
if (model.related('posts_meta').get('email_only') && (newStatus === 'published') && this.hasChanged('status')) {
|
||||||
|
this.set('status', 'draft');
|
||||||
|
}
|
||||||
|
|
||||||
// If a title is set, not the same as the old title, a draft post, and has never been published
|
// If a title is set, not the same as the old title, a draft post, and has never been published
|
||||||
if (prevTitle !== undefined && newTitle !== prevTitle && newStatus === 'draft' && !publishedAt) {
|
if (prevTitle !== undefined && newTitle !== prevTitle && newStatus === 'draft' && !publishedAt) {
|
||||||
ops.push(function updateSlug() {
|
ops.push(function updateSlug() {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
const {BadRequestError} = require('@tryghost/errors');
|
const {BadRequestError} = require('@tryghost/errors');
|
||||||
|
|
||||||
class PostsService {
|
class PostsService {
|
||||||
constructor({mega, apiVersion, urlUtils, i18n, models}) {
|
constructor({mega, apiVersion, urlUtils, i18n, models, isSet}) {
|
||||||
this.apiVersion = apiVersion;
|
this.apiVersion = apiVersion;
|
||||||
this.mega = mega;
|
this.mega = mega;
|
||||||
this.urlUtils = urlUtils;
|
this.urlUtils = urlUtils;
|
||||||
this.i18n = i18n;
|
this.i18n = i18n;
|
||||||
this.models = models;
|
this.models = models;
|
||||||
|
this.isSet = isSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
async editPost(frame) {
|
async editPost(frame) {
|
||||||
|
@ -56,7 +56,9 @@ class PostsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const postPublished = model.wasChanged() && (model.get('status') === 'published') && (model.previous('status') !== 'published');
|
const postPublished = model.wasChanged() && (model.get('status') === 'published') && (model.previous('status') !== 'published');
|
||||||
if (postPublished) {
|
const emailOnlyEnabled = model.related('posts_meta').get('email_only') && this.isSet('emailOnlyPosts');
|
||||||
|
|
||||||
|
if (postPublished || emailOnlyEnabled) {
|
||||||
let postEmail = model.relations.email;
|
let postEmail = model.relations.email;
|
||||||
|
|
||||||
if (!postEmail) {
|
if (!postEmail) {
|
||||||
|
@ -104,6 +106,7 @@ class PostsService {
|
||||||
const getPostServiceInstance = (apiVersion) => {
|
const getPostServiceInstance = (apiVersion) => {
|
||||||
const urlUtils = require('../../../shared/url-utils');
|
const urlUtils = require('../../../shared/url-utils');
|
||||||
const {mega} = require('../mega');
|
const {mega} = require('../mega');
|
||||||
|
const labs = require('../../../shared/labs');
|
||||||
const i18n = require('../../../shared/i18n');
|
const i18n = require('../../../shared/i18n');
|
||||||
const models = require('../../models');
|
const models = require('../../models');
|
||||||
|
|
||||||
|
@ -112,7 +115,8 @@ const getPostServiceInstance = (apiVersion) => {
|
||||||
mega: mega,
|
mega: mega,
|
||||||
urlUtils: urlUtils,
|
urlUtils: urlUtils,
|
||||||
i18n: i18n,
|
i18n: i18n,
|
||||||
models: models
|
models: models,
|
||||||
|
isSet: labs.isSet.bind(labs)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ let request;
|
||||||
|
|
||||||
describe('Posts API (canary)', function () {
|
describe('Posts API (canary)', function () {
|
||||||
let ghostServer;
|
let ghostServer;
|
||||||
let ownerCookie;
|
|
||||||
|
|
||||||
before(function () {
|
before(function () {
|
||||||
return ghost()
|
return ghost()
|
||||||
|
@ -21,10 +20,7 @@ describe('Posts API (canary)', function () {
|
||||||
request = supertest.agent(config.get('url'));
|
request = supertest.agent(config.get('url'));
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return localUtils.doAuth(request, 'users:extra', 'posts', 'emails');
|
return localUtils.doAuth(request, 'users:extra', 'posts', 'emails', 'members');
|
||||||
})
|
|
||||||
.then(function (cookie) {
|
|
||||||
ownerCookie = cookie;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -345,6 +341,50 @@ describe('Posts API (canary)', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('publishes a post with email_only and sends email', async function () {
|
||||||
|
const res = await request
|
||||||
|
.post(localUtils.API.getApiQuery('posts/'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.send({
|
||||||
|
posts: [{
|
||||||
|
title: 'Email me',
|
||||||
|
email_only: true
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
should.exist(res.body.posts);
|
||||||
|
should.exist(res.body.posts[0].title);
|
||||||
|
res.body.posts[0].title.should.equal('Email me');
|
||||||
|
res.body.posts[0].email_only.should.be.true();
|
||||||
|
res.body.posts[0].status.should.equal('draft');
|
||||||
|
|
||||||
|
should.exist(res.headers.location);
|
||||||
|
res.headers.location.should.equal(`http://127.0.0.1:2369${localUtils.API.getApiQuery('posts/')}${res.body.posts[0].id}/`);
|
||||||
|
|
||||||
|
const publishedRes = await request
|
||||||
|
.put(localUtils.API.getApiQuery(`posts/${res.body.posts[0].id}/?email_recipient_filter=all&send_email_when_published=true`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.send({
|
||||||
|
posts: [{
|
||||||
|
status: 'published',
|
||||||
|
updated_at: res.body.posts[0].updated_at
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
should.exist(publishedRes.body.posts);
|
||||||
|
res.body.posts[0].email_only.should.be.true();
|
||||||
|
publishedRes.body.posts[0].status.should.equal('draft');
|
||||||
|
|
||||||
|
should.exist(publishedRes.body.posts[0].email);
|
||||||
|
publishedRes.body.posts[0].email.email_count.should.equal(8);
|
||||||
|
});
|
||||||
|
|
||||||
it('read-only value do not cause errors when edited', function () {
|
it('read-only value do not cause errors when edited', function () {
|
||||||
return request
|
return request
|
||||||
.get(localUtils.API.getApiQuery(`posts/${testUtils.DataGenerator.Content.posts[0].id}/`))
|
.get(localUtils.API.getApiQuery(`posts/${testUtils.DataGenerator.Content.posts[0].id}/`))
|
||||||
|
|
Loading…
Add table
Reference in a new issue