0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Wired up Tiers service to Tiers Content & Admin API

refs https://github.com/TryGhost/Team/issues/2078
This commit is contained in:
Fabien "egg" O'Carroll 2022-10-21 16:21:24 +07:00
parent cc14ce2b20
commit 31610f9b94
6 changed files with 51 additions and 155 deletions

View file

@ -1,8 +1,4 @@
// NOTE: We must not cache references to membersService.api
// as it is a getter and may change during runtime.
const membersService = require('../../services/members');
const allowedIncludes = ['monthly_price', 'yearly_price', 'benefits'];
const tiersService = require('../../services/tiers');
module.exports = {
docName: 'tiers',
@ -11,22 +7,14 @@ module.exports = {
options: [
'limit',
'fields',
'include',
'filter',
'order',
'debug',
'page'
],
permissions: true,
validation: {
options: {
include: {
values: allowedIncludes
}
}
},
async query(frame) {
const page = await membersService.api.productRepository.list(frame.options);
const page = await tiersService.api.browse(frame.options);
return page;
}

View file

@ -1,13 +1,4 @@
const errors = require('@tryghost/errors');
const membersService = require('../../services/members');
const tpl = require('@tryghost/tpl');
const allowedIncludes = ['monthly_price', 'yearly_price', 'benefits'];
const messages = {
productNotFound: 'Tier not found.'
};
const tiersService = require('../../services/tiers');
module.exports = {
docName: 'tiers',
@ -16,7 +7,6 @@ module.exports = {
options: [
'limit',
'fields',
'include',
'filter',
'order',
'debug',
@ -25,48 +15,21 @@ module.exports = {
permissions: {
docName: 'products'
},
validation: {
options: {
include: {
values: allowedIncludes
}
}
},
async query(frame) {
const page = await membersService.api.productRepository.list(frame.options);
const page = await tiersService.api.browse(frame.options);
return page;
}
},
read: {
options: [
'include'
],
headers: {},
data: [
'id'
],
validation: {
options: {
include: {
values: allowedIncludes
}
}
},
permissions: {
docName: 'products'
},
async query(frame) {
const model = await membersService.api.productRepository.get(frame.data, frame.options);
if (!model) {
throw new errors.NotFoundError({
message: tpl(messages.productNotFound)
});
}
return model;
return await tiersService.api.read(frame.data.id);
}
},
@ -84,11 +47,7 @@ module.exports = {
docName: 'products'
},
async query(frame) {
const model = await membersService.api.productRepository.create(
frame.data,
frame.options
);
return model;
return await tiersService.api.add(frame.data);
}
},
@ -111,12 +70,7 @@ module.exports = {
docName: 'products'
},
async query(frame) {
const model = await membersService.api.productRepository.update(
frame.data,
frame.options
);
return model;
return await tiersService.api.edit(frame.options.id, frame.data);
}
}
};

View file

@ -1,5 +1,4 @@
const localUtils = require('../../index');
const labs = require('../../../../../../shared/labs');
const forceActiveFilter = (frame) => {
if (frame.options.filter) {
@ -10,39 +9,31 @@ const forceActiveFilter = (frame) => {
};
function convertTierInput(input) {
const converted = {
id: input.id,
name: input.name,
description: input.description,
slug: input.slug,
active: input.active,
type: input.type,
welcome_page_url: input.welcome_page_url,
created_at: input.created_at,
updated_at: input.updated_at,
visibility: input.visibility
};
const converted = Object.assign({}, input);
if (labs.isSet('freeTrial')) {
converted.trial_days = input.trial_days || 0;
if (Reflect.has(converted, 'active')) {
converted.status = converted.active ? 'active' : 'archived';
delete converted.active;
}
if (input.monthly_price && input.currency) {
converted.monthly_price = {
amount: input.monthly_price,
currency: input.currency
};
if (Reflect.has(converted, 'welcome_page_url')) {
converted.welcomePageURL = converted.welcome_page_url;
delete converted.welcome_page_url;
}
if (input.yearly_price && input.currency) {
converted.yearly_price = {
amount: input.yearly_price,
currency: input.currency
};
if (Reflect.has(converted, 'trial_days')) {
converted.trialDays = converted.trial_days;
delete converted.trial_days;
}
if (input.benefits) {
converted.benefits = input.benefits.map(name => ({name}));
if (Reflect.has(converted, 'monthly_price')) {
converted.monthlyPrice = converted.monthly_price;
delete converted.monthly_price;
}
if (Reflect.has(converted, 'yearly_price')) {
converted.yearlyPrice = converted.yearly_price;
delete converted.yearly_price;
}
return converted;

View file

@ -1,11 +1,6 @@
//@ts-check
const debug = require('@tryghost/debug')('api:endpoints:utils:serializers:output:tiers');
const allowedIncludes = ['monthly_price', 'yearly_price'];
const localUtils = require('../../index');
const {utils} = require('@tryghost/api-framework');
const labs = require('../../../../../../shared/labs');
module.exports = {
browse: createSerializer('browse', paginatedTiers),
read: createSerializer('read', singleTier),
@ -49,11 +44,10 @@ function singleTier(model, _apiConfig, frame) {
/**
* @param {import('bookshelf').Model} tier
* @param {object} options
* @param {object} frame
*
* @returns {SerializedTier}
*/
function serializeTier(tier, options, frame) {
function serializeTier(tier, options) {
const json = tier.toJSON(options);
const serialized = {
@ -61,66 +55,32 @@ function serializeTier(tier, options, frame) {
name: json.name,
description: json.description,
slug: json.slug,
active: json.active,
active: json.status === 'active',
type: json.type,
welcome_page_url: json.welcome_page_url,
created_at: json.created_at,
updated_at: json.updated_at,
welcome_page_url: json.welcomePageURL,
created_at: json.createdAt,
updated_at: json.updatedAt,
visibility: json.visibility,
benefits: null
benefits: json.benefits,
currency: json.currency,
monthly_price: json.monthlyPrice,
yearly_price: json.yearlyPrice,
trial_days: json.trialDays
};
if (labs.isSet('freeTrial')) {
serialized.trial_days = json.trial_days;
}
if (Array.isArray(json.benefits)) {
serialized.benefits = json.benefits.map(benefit => benefit.name);
} else {
if (!Array.isArray(serialized.benefits)) {
serialized.benefits = null;
}
if (serialized.type === 'paid') {
serialized.currency = json.monthlyPrice?.currency;
serialized.monthly_price = json.monthlyPrice?.amount;
serialized.yearly_price = json.yearlyPrice?.amount;
}
if (!localUtils.isContentAPI(frame)) {
const requestedQueryIncludes = frame.original && frame.original.query && frame.original.query.include && frame.original.query.include.split(',') || [];
const requestedOptionsIncludes = utils.options.trimAndLowerCase(frame.original && frame.original.options && frame.original.options.include || []);
return cleanIncludes(
allowedIncludes,
requestedQueryIncludes.concat(requestedOptionsIncludes),
serialized
);
if (serialized.type === 'free') {
delete serialized.currency;
delete serialized.monthly_price;
delete serialized.yearly_price;
}
return serialized;
}
/**
* @template Data
*
* @param {string[]} allowed
* @param {string[]} requested
* @param {Data & Object<string, any>} data
*
* @returns {Data}
*/
function cleanIncludes(allowed, requested, data) {
const cleaned = {
...data
};
for (const include of allowed) {
if (!requested.includes(include)) {
delete cleaned[include];
}
}
return cleaned;
}
/**
* @template Data
* @template Response

View file

@ -4,7 +4,7 @@ exports[`Tiers API Can browse Tiers 1: [body] 1`] = `
Object {
"meta": Object {
"pagination": Object {
"limit": 15,
"limit": 2,
"next": null,
"page": 1,
"pages": 1,
@ -15,7 +15,7 @@ Object {
"tiers": Array [
Object {
"active": true,
"benefits": null,
"benefits": Array [],
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
@ -29,10 +29,12 @@ Object {
},
Object {
"active": true,
"benefits": null,
"benefits": Array [],
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"currency": "USD",
"description": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"monthly_price": 500,
"name": "Default Product",
"slug": "default-product",
"trial_days": 0,
@ -40,6 +42,7 @@ Object {
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"visibility": "public",
"welcome_page_url": "/welcome-paid",
"yearly_price": 5000,
},
],
}

View file

@ -4,7 +4,7 @@ exports[`Tiers Content API Can request only active tiers 1: [body] 1`] = `
Object {
"meta": Object {
"pagination": Object {
"limit": 15,
"limit": 2,
"next": null,
"page": 1,
"pages": 1,
@ -31,10 +31,10 @@ Object {
"active": true,
"benefits": Array [],
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
"currency": "GBP",
"currency": "USD",
"description": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"monthly_price": 1200,
"monthly_price": 500,
"name": "Default Product",
"slug": "default-product",
"trial_days": 0,
@ -42,7 +42,7 @@ Object {
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
"visibility": "public",
"welcome_page_url": "/welcome-paid",
"yearly_price": 12000,
"yearly_price": 5000,
},
],
}
@ -52,7 +52,7 @@ exports[`Tiers Content API Can request only active tiers 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "*",
"cache-control": "public, max-age=0",
"content-length": "730",
"content-length": "727",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Accept-Encoding",