Ghost/ghost/tiers/lib/TiersAPI.js
Fabien "egg" O'Carroll 6614aa9070 Fixed add method for TiersAPI
refs https://github.com/TryGhost/Team/issues/2078

The check for creating free Tiers needs to be explicit, rather than implicit
because the type is optional, we only want to error if it is explicitly passed
as "free", not if it is missing as "paid".
2022-10-20 11:56:46 +07:00

144 lines
3.8 KiB
JavaScript

const ObjectID = require('bson-objectid').default;
const {BadRequestError} = require('@tryghost/errors');
const Tier = require('./Tier');
/**
* @typedef {object} ITierRepository
* @prop {(id: ObjectID) => Promise<Tier>} getById
* @prop {(tier: Tier) => Promise<void>} save
* @prop {(options?: {filter?: string}) => Promise<Tier[]>} getAll
*/
/**
* @typedef {object} ISlugService
* @prop {(input: string) => Promise<string>} generate
*/
/**
* @template {Model}
* @typedef {object} Page<Model>
* @prop {Model[]} data
* @prop {object} meta
* @prop {object} meta.pagination
* @prop {number} meta.pagination.page - The current page
* @prop {number} meta.pagination.pages - The total number of pages
* @prop {number} meta.pagination.limit - The limit of models per page
* @prop {number} meta.pagination.total - The totaL number of models across all pages
* @prop {number|null} meta.pagination.prev - The number of the previous page, or null if there isn't one
* @prop {number|null} meta.pagination.next - The number of the next page, or null if there isn't one
*/
module.exports = class TiersAPI {
/** @type {ITierRepository} */
#repository;
/** @type {ISlugService} */
#slugService;
constructor(deps) {
this.#repository = deps.repository;
this.#slugService = deps.slugService;
}
/**
* @param {object} [options]
* @param {string} [options.filter] - An NQL filter string
*
* @returns {Promise<Page<Tier>>}
*/
async browse(options = {}) {
const tiers = await this.#repository.getAll(options);
return {
data: tiers,
meta: {
pagination: {
page: 1,
pages: 1,
limit: tiers.length,
total: tiers.length,
prev: null,
next: null
}
}
};
}
/**
* @param {string} idString
*
* @returns {Promise<Tier>}
*/
async read(idString) {
const id = ObjectID.createFromHexString(idString);
const tier = await this.#repository.getById(id);
return tier;
}
/**
* @param {string} id
* @param {object} data
* @returns {Promise<Tier>}
*/
async edit(idString, data) {
const id = ObjectID.createFromHexString(idString);
const tier = await this.#repository.getById(id);
const editableProperties = [
'name',
'benefits',
'description',
'visibility',
'active',
'trialDays',
'currency',
'monthlyPrice',
'yearlyPrice',
'welcomePageURL'
];
for (const editableProperty of editableProperties) {
if (Reflect.has(data, editableProperty)) {
tier[editableProperty] = data[editableProperty];
}
}
await this.#repository.save(tier);
return tier;
}
/**
* @param {object} data
* @returns {Promise<Tier>}
*/
async add(data) {
if (data.type === 'free') {
throw new BadRequestError({
message: 'Cannot create free Tier'
});
}
const slug = await this.#slugService.generate(data.slug || data.name);
const tier = await Tier.create({
slug,
type: 'paid',
status: 'active',
visibility: data.visibility,
name: data.name,
description: data.description,
benefits: data.benefits,
welcomePageURL: data.welcomePageURL,
monthlyPrice: data.monthlyPrice,
yearlyPrice: data.yearlyPrice,
currency: data.currency,
trialDays: data.trialDays
});
await this.#repository.save(tier);
return tier;
}
};