UNPKG

ghost

Version:

The professional publishing platform

184 lines (153 loc) 6.28 kB
const DomainEvents = require('@tryghost/domain-events'); const MentionCreatedEvent = require('../mentions/MentionCreatedEvent'); const logging = require('@tryghost/logging'); class RecommendationServiceWrapper { /** * @type {import('./service').RecommendationRepository} */ repository; /** * @type {import('./service').BookshelfClickEventRepository} */ clickEventRepository; /** * @type {import('./service').BookshelfSubscribeEventRepository} */ subscribeEventRepository; /** * @type {import('./service').RecommendationController} */ controller; /** * @type {import('./service').RecommendationService} */ service; /** * @type {import('./service').IncomingRecommendationController} */ incomingRecommendationController; /** * @type {import('./service').IncomingRecommendationService} */ incomingRecommendationService; init() { const config = require('../../../shared/config'); if (config.get('services:recommendations:enabled') === false) { logging.info('[Recommendations] Service is disabled via config'); return; } if (this.repository) { return; } const urlUtils = require('../../../shared/url-utils'); const models = require('../../models'); const sentry = require('../../../shared/sentry'); const settings = require('../settings'); const RecommendationEnablerService = require('./RecommendationEnablerService'); const { BookshelfRecommendationRepository, RecommendationService, RecommendationController, WellknownService, BookshelfClickEventRepository, IncomingRecommendationController, IncomingRecommendationService, IncomingRecommendationEmailRenderer, RecommendationMetadataService } = require('./service'); const mentions = require('../mentions'); if (!mentions.sendingService || !mentions.api) { // eslint-disable-next-line ghost/ghost-custom/no-native-error throw new Error('MentionSendingService not intialized, but this is a dependency of RecommendationServiceWrapper. Check boot order.'); } const wellknownService = new WellknownService({ dir: config.getContentPath('public'), urlUtils }); const settingsService = settings.getSettingsBREADServiceInstance(); const recommendationEnablerService = new RecommendationEnablerService({settingsService}); this.repository = new BookshelfRecommendationRepository(models.Recommendation, { sentry }); this.clickEventRepository = new BookshelfClickEventRepository(models.RecommendationClickEvent, { sentry }); this.subscribeEventRepository = new BookshelfClickEventRepository(models.RecommendationSubscribeEvent, { sentry }); const oembedService = require('../oembed'); const externalRequest = require('../../../server/lib/request-external.js'); const recommendationMetadataService = new RecommendationMetadataService({ oembedService, externalRequest }); this.service = new RecommendationService({ repository: this.repository, recommendationEnablerService, wellknownService, mentionSendingService: mentions.sendingService, clickEventRepository: this.clickEventRepository, subscribeEventRepository: this.subscribeEventRepository, recommendationMetadataService }); const mail = require('../mail'); const mailer = new mail.GhostMailer(); const emailService = { async send(to, subject, html, text) { return mailer.send({ to, subject, html, text }); } }; this.incomingRecommendationService = new IncomingRecommendationService({ mentionsApi: mentions.api, recommendationService: this.service, emailService, async getEmailRecipients() { const users = await models.User.getEmailAlertUsers('recommendation-received'); return users.map((model) => { return { email: model.email, slug: model.slug }; }); }, emailRenderer: new IncomingRecommendationEmailRenderer({ staffService: require('../staff') }) }); this.controller = new RecommendationController({ service: this.service }); this.incomingRecommendationController = new IncomingRecommendationController({ service: this.incomingRecommendationService }); this.service.init().catch(logging.error); this.incomingRecommendationService.init().catch(logging.error); const PATH_SUFFIX = '/.well-known/recommendations.json'; function isRecommendationUrl(url) { return url.pathname.endsWith(PATH_SUFFIX); } // Add mapper to WebmentionMetadata mentions.metadata.addMapper((url) => { if (isRecommendationUrl(url)) { // Strip p const newUrl = new URL(url.toString()); newUrl.pathname = newUrl.pathname.slice(0, -PATH_SUFFIX.length); return newUrl; } }); // Listen for incoming webmentions DomainEvents.subscribe(MentionCreatedEvent, async (event) => { // Check if this is a recommendation if (event.data.mention.verified && isRecommendationUrl(event.data.mention.source)) { logging.info('[INCOMING RECOMMENDATION] Received recommendation from ' + event.data.mention.source); await this.incomingRecommendationService.sendRecommendationEmail(event.data.mention); } }); } } module.exports = RecommendationServiceWrapper;