forked from TryGhost/Ghost
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
closes TryGhost#10060 - Implemented scheduling for posts and pages - Added cache invalidation when scheduling - Refactored admin token eneration function to accept existing key as parameter in tests - Added Ghost Scheduler Integration fixture - Added fixture for permissions for post publish action - Migrated getScheduled method to v2 - Did not add support for 'from' and 'to' parameters as they were not used by DefaultScheduler - This method needs rethinking in a long run as it's an ugly hack and should rather become proper endpoint that returns JSON data instead of models - Removed unused auth middleware from v2 routes - Added internal scheduler role - Implemetnted transactions in v2 frame - This takes into account scenario mentioned in c93f03b - Specifically: >if two queries happening in a transaction we have to signalise knex/mysql that we select for an update otherwise the following case happens: you fetch posts for an update a user requests comes in and updates the post (e.g. sets title to "X") you update the fetched posts, title would get overriden to the old one
- Loading branch information
Showing
16 changed files
with
395 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
const _ = require('lodash'); | ||
const moment = require('moment'); | ||
const config = require('../../config'); | ||
const models = require('../../models'); | ||
const urlUtils = require('../../lib/url-utils'); | ||
const common = require('../../lib/common'); | ||
const api = require('./index'); | ||
|
||
module.exports = { | ||
docName: 'schedules', | ||
publish: { | ||
headers: {}, | ||
options: [ | ||
'id', | ||
'resource' | ||
], | ||
data: [ | ||
'force' | ||
], | ||
validation: { | ||
options: { | ||
id: { | ||
required: true | ||
}, | ||
resource: { | ||
required: true, | ||
values: ['posts', 'pages'] | ||
} | ||
} | ||
}, | ||
permissions: { | ||
docName: 'posts' | ||
}, | ||
query(frame) { | ||
let resource; | ||
const resourceType = frame.options.resource; | ||
const publishAPostBySchedulerToleranceInMinutes = config.get('times').publishAPostBySchedulerToleranceInMinutes; | ||
|
||
return models.Base.transaction((transacting) => { | ||
const options = { | ||
transacting: transacting, | ||
status: 'scheduled', | ||
forUpdate: true, | ||
id: frame.options.id, | ||
context: { | ||
internal: true | ||
} | ||
}; | ||
|
||
return api[resourceType].read({id: frame.options.id}, options) | ||
.then((result) => { | ||
resource = result[resourceType][0]; | ||
const publishedAtMoment = moment(resource.published_at); | ||
|
||
if (publishedAtMoment.diff(moment(), 'minutes') > publishAPostBySchedulerToleranceInMinutes) { | ||
return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.job.notFound')})); | ||
} | ||
|
||
if (publishedAtMoment.diff(moment(), 'minutes') < publishAPostBySchedulerToleranceInMinutes * -1 && frame.data.force !== true) { | ||
return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.job.publishInThePast')})); | ||
} | ||
|
||
const editedResource = {}; | ||
editedResource[resourceType] = [{ | ||
status: 'published', | ||
updated_at: moment(resource.updated_at).toISOString(true) | ||
}]; | ||
|
||
return api[resourceType].edit( | ||
editedResource, | ||
_.pick(options, ['context', 'id', 'transacting', 'forUpdate']) | ||
); | ||
}) | ||
.then((result) => { | ||
const scheduledResource = result[resourceType][0]; | ||
|
||
if ( | ||
(scheduledResource.status === 'published' && resource.status !== 'published') || | ||
(scheduledResource.status === 'draft' && resource.status === 'published') | ||
) { | ||
this.headers.cacheInvalidate = true; | ||
} else if ( | ||
(scheduledResource.status === 'draft' && resource.status !== 'published') || | ||
(scheduledResource.status === 'scheduled' && resource.status !== 'scheduled') | ||
) { | ||
this.headers.cacheInvalidate = { | ||
value: urlUtils.urlFor({ | ||
relativeUrl: urlUtils.urlJoin('/p', scheduledResource.uuid, '/') | ||
}) | ||
}; | ||
} else { | ||
this.headers.cacheInvalidate = false; | ||
} | ||
|
||
return result; | ||
}); | ||
}); | ||
} | ||
}, | ||
|
||
getScheduled: { | ||
// NOTE: this method is for internal use only by DefaultScheduler | ||
// it is not exposed anywhere! | ||
permissions: false, | ||
validation: { | ||
options: { | ||
resource: { | ||
required: true, | ||
values: ['posts', 'pages'] | ||
} | ||
} | ||
}, | ||
query(frame) { | ||
const resourceType = frame.options.resource; | ||
const resourceModel = (resourceType === 'posts') ? 'Post' : 'Page'; | ||
|
||
const cleanOptions = {}; | ||
cleanOptions.filter = 'status:scheduled'; | ||
cleanOptions.columns = ['id', 'published_at', 'created_at']; | ||
|
||
return models[resourceModel].findAll(cleanOptions) | ||
.then((result) => { | ||
let response = {}; | ||
response[resourceType] = result; | ||
|
||
return response; | ||
}); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
all(model, apiConfig, frame) { | ||
frame.response = model; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.