🐛 Fixed 'comped' flag behavior in Member API (#15030)

closes https://github.com/TryGhost/Team/issues/1674

- The comped flag in Members API unintentionally stopped working when v3 API was dropped with the release of Ghost v5. The flag is deprecated but should be back-compatible for now - we don't want to break integratons like Zapier.
- To properly deprecate the flag we need to plan it's removal and start signalling about it through the version headers

Co-authored-by: Simon Backx <simon@ghost.org>
This commit is contained in:
naz 2022-07-15 22:16:06 +12:00 committed by GitHub
parent e91beb72e8
commit 6901c3c435
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 27 deletions

View File

@ -85,7 +85,7 @@
"@tryghost/logging": "2.2.3",
"@tryghost/magic-link": "1.0.26",
"@tryghost/member-events": "0.4.6",
"@tryghost/members-api": "8.2.0",
"@tryghost/members-api": "8.2.1",
"@tryghost/members-events-service": "0.4.3",
"@tryghost/members-importer": "0.5.16",
"@tryghost/members-offers": "0.11.6",

View File

@ -880,7 +880,7 @@ Object {
"members": Array [
Object {
"avatar_image": null,
"comped": false,
"comped": true,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"email": "compedtest@test.com",
"email_count": 0,
@ -893,10 +893,25 @@ Object {
"name": "Name",
"newsletters": Any<Array>,
"note": null,
"status": "free",
"status": "comped",
"subscribed": true,
"subscriptions": Any<Array>,
"tiers": Array [],
"tiers": Array [
Object {
"active": true,
"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\\}/,
"monthly_price_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Default Product",
"slug": "default-product",
"type": "paid",
"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_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
},
],
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
},
@ -908,7 +923,7 @@ exports[`Members API Can add complimentary subscription (out of date) 4: [header
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "1100",
"content-length": "2511",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",
@ -1261,7 +1276,22 @@ Object {
"status": "comped",
"subscribed": true,
"subscriptions": Any<Array>,
"tiers": Any<Array>,
"tiers": Array [
Object {
"active": true,
"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\\}/,
"monthly_price_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Default Product",
"slug": "default-product",
"type": "paid",
"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_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
},
],
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
},
@ -1273,7 +1303,7 @@ exports[`Members API Can create a member with an existing complimentary subscrip
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "2424",
"content-length": "2562",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -1342,7 +1372,7 @@ exports[`Members API Can create a member with an existing paid subscription 2: [
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "2499",
"content-length": "2548",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -1640,9 +1670,9 @@ exports[`Members API Can fetch member counts stats 1: [body] 1`] = `
Object {
"data": Array [
Object {
"comped": 3,
"comped": 4,
"date": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
"free": 5,
"free": 4,
"paid": 2,
},
],
@ -2001,6 +2031,28 @@ Object {
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
},
Object {
"avatar_image": null,
"comped": true,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"email": "compedtest@test.com",
"email_count": 0,
"email_open_rate": null,
"email_opened_count": 0,
"geolocation": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"labels": Any<Array>,
"last_seen_at": null,
"name": "Name",
"newsletters": Any<Array>,
"note": null,
"status": "comped",
"subscribed": true,
"subscriptions": Any<Array>,
"tiers": Any<Array>,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
},
Object {
"avatar_image": null,
"comped": false,
@ -2075,7 +2127,7 @@ Object {
"page": 1,
"pages": 1,
"prev": null,
"total": 7,
"total": 8,
},
},
}
@ -2085,7 +2137,7 @@ exports[`Members API Can filter on tier slug 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "17658",
"content-length": "20245",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",

View File

@ -78,6 +78,14 @@ function buildMemberWithIncludesSnapshot(options) {
};
}
const tierMatcher = {
id: anyObjectId,
created_at: anyISODateTime,
updated_at: anyISODateTime,
monthly_price_id: anyObjectId,
yearly_price_id: anyObjectId
};
const memberMatcherShallowIncludes = {
id: anyObjectId,
uuid: anyUuid,
@ -88,9 +96,16 @@ const memberMatcherShallowIncludes = {
newsletters: anyArray
};
const memberMatcherShallowIncludesWithTiers = {
...memberMatcherShallowIncludes,
tiers: anyArray
const buildMemberMatcherShallowIncludesWithTiers = (tiersCount) => {
let tiers = anyArray;
if (tiersCount) {
tiers = new Array(tiers).fill(tierMatcher);
}
return {
...memberMatcherShallowIncludes,
tiers
};
};
let agent;
@ -340,7 +355,7 @@ describe('Members API', function () {
.get(`/members/${testUtils.DataGenerator.Content.members[0].id}/?include=tiers`)
.expectStatus(200)
.matchBodySnapshot({
members: new Array(1).fill(memberMatcherShallowIncludesWithTiers)
members: new Array(1).fill(buildMemberMatcherShallowIncludesWithTiers())
})
.matchHeaderSnapshot({
etag: anyEtag
@ -554,12 +569,12 @@ describe('Members API', function () {
const newMember = body.members[0];
const {body: body2} = await agent
await agent
.put(`/members/${newMember.id}/`)
.body({members: [compedPayload]})
.expectStatus(200)
.matchBodySnapshot({
members: new Array(1).fill(memberMatcherShallowIncludes)
members: new Array(1).fill(buildMemberMatcherShallowIncludesWithTiers(1))
})
.matchHeaderSnapshot({
etag: anyEtag
@ -571,6 +586,9 @@ describe('Members API', function () {
asserts: [{
from_status: null,
to_status: 'free'
}, {
from_status: 'free',
to_status: 'comped'
}]
});
@ -809,7 +827,7 @@ describe('Members API', function () {
};
const fakeSubscription = {
id: 'sub_1',
id: 'sub_2',
customer: 'cus_1234',
status: 'active',
cancel_at_period_end: false,
@ -872,7 +890,7 @@ describe('Members API', function () {
updated_at: anyISODateTime,
labels: anyArray,
subscriptions: anyArray,
tiers: anyArray,
tiers: new Array(1).fill(tierMatcher),
newsletters: new Array(1).fill(newsletterSnapshot)
})
})
@ -1637,11 +1655,11 @@ describe('Members API', function () {
});
it('Can filter on tier slug', async function () {
const res = await agent
await agent
.get('/members/?include=tiers&filter=tier:default-product')
.expectStatus(200)
.matchBodySnapshot({
members: new Array(7).fill(memberMatcherShallowIncludesWithTiers)
members: new Array(8).fill(buildMemberMatcherShallowIncludesWithTiers())
})
.matchHeaderSnapshot({
etag: anyEtag
@ -2036,7 +2054,7 @@ describe('Members API Bulk operations', function () {
.matchHeaderSnapshot({
etag: anyEtag
});
const updatedModel = await models.Member.findOne({id: member.id}, {withRelated: 'newsletters'});
should(updatedModel.relations.newsletters.models.length).equal(0, 'This member should be unsubscribed from all newsletters');

View File

@ -1909,10 +1909,10 @@
"@tryghost/domain-events" "^0.1.14"
"@tryghost/member-events" "^0.4.6"
"@tryghost/members-api@8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-8.2.0.tgz#11e043a716e740f42c6590be44072ff4d3ef884a"
integrity sha512-MCLgN/ixaQDIhmNbXpofoTF9pBgbbLAUcNsoM/WBIPJkzAO7yYL/Np5xtvg4nVrH+/6SrAzYe/IH8wB0mc5QVA==
"@tryghost/members-api@8.2.1":
version "8.2.1"
resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-8.2.1.tgz#c2edc1a6613e9ea707493ba680de026615736c0b"
integrity sha512-MTrb0t6wHGIap4mSl95BvWi0JfCoaw2xs5bQEbGRNxVzG2G3e7XgLylrucM30QIVt4AtNT1afCnOBlYMcfPbiQ==
dependencies:
"@nexes/nql" "^0.6.0"
"@tryghost/debug" "^0.1.2"