Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions ghost/core/core/boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,13 @@ async function initCore({ghostServer, config, frontend}) {
});
debug('End: Url Service');

// Gift links service: wires the (knex-backed) repository once the DB is ready.
debug('Begin: Gift Links Service');
const giftLinksService = require('./server/services/gift-links');
giftLinksService.init();
debug('End: Gift Links Service');
// Gift links: construct the service against the ready DB and inject it into the API controller.
debug('Begin: Gift Links');
const {GiftLinksService} = require('./server/services/gift-links');
const {knex: giftLinksKnex} = require('./server/data/db');
const giftLinksEndpoint = require('./server/api/endpoints/gift-links');
giftLinksEndpoint.controller = giftLinksEndpoint.createController(new GiftLinksService({knex: giftLinksKnex}));
debug('End: Gift Links');

if (ghostServer) {
// Job Service allows parts of Ghost to run in the background
Expand Down
102 changes: 54 additions & 48 deletions ghost/core/core/server/api/endpoints/gift-links.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {service} from '../../services/gift-links';
import type {GiftLinksService} from '../../services/gift-links';

// permissions is untyped JS; require, don't import.
// eslint-disable-next-line @typescript-eslint/no-require-imports
Expand All @@ -21,59 +21,65 @@ async function assertCanManageGiftLink(frame: Frame): Promise<void> {

const noCacheInvalidation = {cacheInvalidate: false};

const controller = {
docName: 'gift_links',
function createController(service: GiftLinksService) {
return {
docName: 'gift_links',

read: {
headers: noCacheInvalidation,
options: ['id'],
validation: {options: {id: {required: true}}},
permissions(frame: Frame) {
return assertCanManageGiftLink(frame);
read: {
headers: noCacheInvalidation,
options: ['id'],
validation: {options: {id: {required: true}}},
permissions(frame: Frame) {
return assertCanManageGiftLink(frame);
},
query(frame: Frame) {
return service.getPost(frame.options.id);
}
},
query(frame: Frame) {
return service!.getPost(frame.options.id);
}
},

issue: {
headers: noCacheInvalidation,
statusCode: 200,
options: ['id'],
validation: {options: {id: {required: true}}},
permissions(frame: Frame) {
return assertCanManageGiftLink(frame);
issue: {
headers: noCacheInvalidation,
statusCode: 200,
options: ['id'],
validation: {options: {id: {required: true}}},
permissions(frame: Frame) {
return assertCanManageGiftLink(frame);
},
query(frame: Frame) {
return service.issue(frame.options.id);
}
},
query(frame: Frame) {
return service!.issue(frame.options.id);
}
},

reissue: {
headers: noCacheInvalidation,
statusCode: 200,
options: ['id'],
validation: {options: {id: {required: true}}},
permissions(frame: Frame) {
return assertCanManageGiftLink(frame);
reissue: {
headers: noCacheInvalidation,
statusCode: 200,
options: ['id'],
validation: {options: {id: {required: true}}},
permissions(frame: Frame) {
return assertCanManageGiftLink(frame);
},
query(frame: Frame) {
return service.reissue(frame.options.id);
}
},
query(frame: Frame) {
return service!.reissue(frame.options.id);
}
},

revokeAll: {
headers: noCacheInvalidation,
statusCode: 200,
permissions(frame: Frame) {
return permissionsService.canThis(frame.options.context).revokeAll.gift_link();
},
async query() {
const count = await service!.revokeAll();
return {count};
revokeAll: {
headers: noCacheInvalidation,
statusCode: 200,
permissions(frame: Frame) {
return permissionsService.canThis(frame.options.context).revokeAll.gift_link();
},
async query() {
const count = await service.revokeAll();
return {count};
}
}
}
};
};
}

// module.exports (not export): the API framework loads controllers via require().
module.exports = controller;
// module.exports (not export): boot (the composition root) calls createController with the
// constructed service and assigns the result to `controller`; the API endpoints index reads it.
module.exports = {
createController,
controller: undefined as ReturnType<typeof createController> | undefined
};
2 changes: 1 addition & 1 deletion ghost/core/core/server/api/endpoints/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ module.exports = {
},

get giftLinks() {
return apiFramework.pipeline(require('./gift-links'), localUtils);
return apiFramework.pipeline(require('./gift-links').controller, localUtils);
},

get giftReminders() {
Expand Down
16 changes: 1 addition & 15 deletions ghost/core/core/server/services/gift-links/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1 @@
import {GiftLinksService} from './service';

// Set by init() at boot, not at import: knex only exists once the DB has connected.
export let service: GiftLinksService | undefined;

export function init(): void {
if (service) {
return;
}

// eslint-disable-next-line @typescript-eslint/no-require-imports
const {knex} = require('../../data/db');

service = new GiftLinksService({knex});
}
export {GiftLinksService} from './service';
Loading