2022-05-05 07:16:20 +03:00
|
|
|
const path = require('path');
|
2022-05-09 13:14:41 +03:00
|
|
|
const VersionNotificationsDataService = require('@tryghost/version-notifications-data-service');
|
2022-05-05 07:16:20 +03:00
|
|
|
const EmailContentGenerator = require('@tryghost/email-content-generator');
|
|
|
|
|
2022-04-19 15:42:31 +03:00
|
|
|
class APIVersionCompatibilityService {
|
2022-04-20 06:08:56 +03:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Object} options
|
2022-05-09 13:14:41 +03:00
|
|
|
* @param {Object} options.UserModel - ghost user model
|
2022-05-10 12:33:15 +03:00
|
|
|
* @param {Object} options.ApiKeyModel - ghost api key model
|
2022-05-09 13:14:41 +03:00
|
|
|
* @param {Object} options.settingsService - ghost settings service
|
2022-05-05 06:15:54 +03:00
|
|
|
* @param {(Object: {subject: String, to: String, text: String, html: String}) => Promise<any>} options.sendEmail - email sending function
|
2022-05-05 07:16:20 +03:00
|
|
|
* @param {Function} options.getSiteUrl
|
|
|
|
* @param {Function} options.getSiteTitle
|
2022-04-20 06:08:56 +03:00
|
|
|
*/
|
2022-05-10 12:33:15 +03:00
|
|
|
constructor({UserModel, ApiKeyModel, settingsService, sendEmail, getSiteUrl, getSiteTitle}) {
|
2022-04-19 15:42:31 +03:00
|
|
|
this.sendEmail = sendEmail;
|
2022-05-09 13:14:41 +03:00
|
|
|
|
|
|
|
this.versionNotificationsDataService = new VersionNotificationsDataService({
|
|
|
|
UserModel,
|
2022-05-10 12:33:15 +03:00
|
|
|
ApiKeyModel,
|
2022-05-09 13:14:41 +03:00
|
|
|
settingsService
|
|
|
|
});
|
2022-05-05 07:16:20 +03:00
|
|
|
|
|
|
|
this.emailContentGenerator = new EmailContentGenerator({
|
|
|
|
getSiteUrl,
|
|
|
|
getSiteTitle,
|
|
|
|
templatesDir: path.join(__dirname, 'templates')
|
|
|
|
});
|
2022-04-19 15:42:31 +03:00
|
|
|
}
|
|
|
|
|
2022-05-05 09:51:47 +03:00
|
|
|
/**
|
|
|
|
* Version mismatch handler doing the logic of picking a template and sending a notification email
|
|
|
|
* @param {Object} options
|
|
|
|
* @param {string} options.acceptVersion - client's accept-version header value
|
|
|
|
* @param {string} options.contentVersion - server's content-version header value
|
2022-05-10 12:33:15 +03:00
|
|
|
* @param {string} options.apiKeyValue - key value (secret for Content API and kid for Admin API) used to access the API
|
|
|
|
* @param {string} options.apiKeyType - key type used to access the API
|
2022-05-05 09:51:47 +03:00
|
|
|
* @param {string} options.requestURL - url that was requested and failed compatibility test
|
|
|
|
* @param {string} [options.userAgent] - client's user-agent header value
|
|
|
|
*/
|
2022-05-10 12:33:15 +03:00
|
|
|
async handleMismatch({acceptVersion, contentVersion, apiKeyValue, apiKeyType, requestURL, userAgent = ''}) {
|
2022-05-09 13:14:41 +03:00
|
|
|
if (!await this.versionNotificationsDataService.fetchNotification(acceptVersion)) {
|
2024-05-02 13:51:27 +03:00
|
|
|
const integration = await this.versionNotificationsDataService.getIntegration(apiKeyValue, apiKeyType);
|
|
|
|
|
|
|
|
// We couldn't find the integration
|
|
|
|
if (!integration) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-30 12:57:02 +03:00
|
|
|
const {
|
|
|
|
name: integrationName,
|
|
|
|
type: integrationType
|
2024-05-02 13:51:27 +03:00
|
|
|
} = integration;
|
2023-01-30 12:57:02 +03:00
|
|
|
|
|
|
|
// @NOTE: "internal" or "core" integrations (https://ghost.notion.site/Data-Types-e5dc54dd0078443f9afd6b2abda443c4)
|
|
|
|
// are maintained by Ghost team, so there is no sense notifying the instance owner about it's incompatibility.
|
|
|
|
// The other two integration types: "builtin" and "custom", is when we want to notify about incompatibility.
|
|
|
|
if (['internal', 'core'].includes(integrationType)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-04 06:05:48 +03:00
|
|
|
const trimmedUseAgent = userAgent.split('/')[0];
|
2022-05-09 13:14:41 +03:00
|
|
|
const emails = await this.versionNotificationsDataService.getNotificationEmails();
|
2022-05-05 07:16:20 +03:00
|
|
|
|
2022-04-21 10:54:28 +03:00
|
|
|
for (const email of emails) {
|
2022-05-05 07:43:55 +03:00
|
|
|
const template = (trimmedUseAgent === 'Zapier')
|
|
|
|
? 'zapier-mismatch'
|
|
|
|
: 'generic-mismatch';
|
|
|
|
|
|
|
|
const subject = (trimmedUseAgent === 'Zapier')
|
|
|
|
? 'Attention required: One of your Zaps has failed'
|
2022-05-11 05:08:32 +03:00
|
|
|
: `Attention required: Your ${integrationName} integration has failed`;
|
2022-05-05 07:43:55 +03:00
|
|
|
|
2022-05-05 07:16:20 +03:00
|
|
|
const {html, text} = await this.emailContentGenerator.getContent({
|
2022-05-05 07:32:52 +03:00
|
|
|
template,
|
2022-05-05 07:16:20 +03:00
|
|
|
data: {
|
|
|
|
acceptVersion,
|
|
|
|
contentVersion,
|
2022-05-10 12:33:15 +03:00
|
|
|
clientName: integrationName,
|
2022-05-05 09:51:47 +03:00
|
|
|
recipientEmail: email,
|
|
|
|
requestURL: requestURL
|
2022-05-05 07:16:20 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-04-21 10:54:28 +03:00
|
|
|
await this.sendEmail({
|
2022-05-05 07:43:55 +03:00
|
|
|
subject,
|
2022-04-21 10:54:28 +03:00
|
|
|
to: email,
|
2022-05-05 07:16:20 +03:00
|
|
|
html,
|
|
|
|
text
|
2022-04-21 10:54:28 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-05-09 13:14:41 +03:00
|
|
|
await this.versionNotificationsDataService.saveNotification(acceptVersion);
|
2022-04-20 06:08:56 +03:00
|
|
|
}
|
2022-04-19 15:42:31 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = APIVersionCompatibilityService;
|