diff --git a/apps/admin-x-settings/package.json b/apps/admin-x-settings/package.json index 38739bff11..08c63e7cde 100644 --- a/apps/admin-x-settings/package.json +++ b/apps/admin-x-settings/package.json @@ -41,7 +41,7 @@ "@tryghost/color-utils": "0.2.2", "@tryghost/kg-unsplash-selector": "0.2.4", "@tryghost/limit-service": "1.2.14", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/timezone-data": "0.4.3", "react": "18.3.1", "react-dom": "18.3.1", diff --git a/ghost/admin/app/controllers/members.js b/ghost/admin/app/controllers/members.js index 9279418d23..08b0b9d3f6 100644 --- a/ghost/admin/app/controllers/members.js +++ b/ghost/admin/app/controllers/members.js @@ -209,10 +209,8 @@ export default class MembersController extends Controller { return uniqueColumns.splice(0, 2); // Maximum 2 columns } - /* Due to a limitation with NQL when multiple member filters are used in combination, we currently have a safeguard around member bulk deletion. - * Member bulk deletion is not permitted when: - * 1) Multiple newsletters exist, and 2 or more newsletter filters are in use - * 2) If any of the following Stripe filters are used, even once: + /* + * Due to a limitation with NQL, member bulk deletion is not permitted if any of the following Stripe subscription filters is used: * - Billing period * - Stripe subscription status * - Paid start date @@ -220,19 +218,15 @@ export default class MembersController extends Controller { * - Subscription started on post/page * - Offers * - * See issue https://linear.app/tryghost/issue/ENG-1484 for more context + * For more context, see: + * - https://linear.app/tryghost/issue/ENG-1484 + * - https://linear.app/tryghost/issue/ENG-1466 */ get isBulkDeletePermitted() { if (!this.isFiltered) { return false; } - const newsletterFilters = this.filters.filter(f => f.group === 'Newsletters'); - - if (newsletterFilters && newsletterFilters.length >= 2) { - return false; - } - const stripeFilters = this.filters.filter(f => [ 'subscriptions.plan_interval', 'subscriptions.status', diff --git a/ghost/admin/package.json b/ghost/admin/package.json index 85d95f6b8c..200ec122b2 100644 --- a/ghost/admin/package.json +++ b/ghost/admin/package.json @@ -53,7 +53,7 @@ "@tryghost/koenig-lexical": "1.3.25", "@tryghost/limit-service": "1.2.14", "@tryghost/members-csv": "0.0.0", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/nql-lang": "0.6.1", "@tryghost/string": "0.2.12", "@tryghost/timezone-data": "0.4.3", diff --git a/ghost/admin/tests/acceptance/members-test.js b/ghost/admin/tests/acceptance/members-test.js index 50ab1eeee2..babc7ceeb6 100644 --- a/ghost/admin/tests/acceptance/members-test.js +++ b/ghost/admin/tests/acceptance/members-test.js @@ -143,63 +143,23 @@ describe('Acceptance: Members', function () { .to.equal('example@domain.com'); }); - /* Due to a limitation with NQL when multiple member filters are used in combination, we currently have a safeguard around member bulk deletion. - * Member bulk deletion is not permitted when: - * 1) Multiple newsletters exist, and 2 or more newsletter filters are in use - * 2) If any of the following Stripe filters are used, even once: - * - Billing period - * - Stripe subscription status - * - Paid start date - * - Next billing date - * - Subscription started on post/page - * - Offers - * - * See code: ghost/admin/app/controllers/members.js:isBulkDeletePermitted - * See issue https://linear.app/tryghost/issue/ENG-1484 for more context - * - * TODO: delete this block of tests once the guardrail has been removed + /* + * Due to a limitation with NQL, member bulk deletion is not permitted if any of the following Stripe subscription filters is used: + * - Billing period + * - Stripe subscription status + * - Paid start date + * - Next billing date + * - Subscription started on post/page + * - Offers + * + * For more context, see: + * - https://linear.app/tryghost/issue/ENG-1484 + * - https://linear.app/tryghost/issue/ENG-1466 + * + * See code: ghost/admin/app/controllers/members.js:isBulkDeletePermitted + * TODO: delete this block of tests once the guardrail has been removed */ describe('[Temp] Guardrail against bulk deletion', function () { - it('cannot bulk delete members if more than 1 newsletter filter is used', async function () { - // Create two newsletters and members subscribed to 1 or 2 newsletters - const newsletterOne = this.server.create('newsletter'); - const newsletterTwo = this.server.create('newsletter'); - this.server.createList('member', 2).forEach(member => member.update({newsletters: [newsletterOne], email_disabled: 0})); - this.server.createList('member', 2).forEach(member => member.update({newsletters: [newsletterOne, newsletterTwo], email_disabled: 0})); - - await visit('/members'); - expect(findAll('[data-test-member]').length).to.equal(4); - - // The delete button should not be visible by default - await click('[data-test-button="members-actions"]'); - expect(find('[data-test-button="delete-selected"]')).to.not.exist; - - // Apply a first filter - await click('[data-test-button="members-filter-actions"]'); - await fillIn('[data-test-members-filter="0"] [data-test-select="members-filter"]', `newsletters.slug:${newsletterOne.slug}`); - await click(`[data-test-button="members-apply-filter"]`); - - expect(findAll('[data-test-member]').length).to.equal(4); - expect(currentURL()).to.equal(`/members?filter=(newsletters.slug%3A${newsletterOne.slug}%2Bemail_disabled%3A0)`); - - // Bulk deletion is permitted - await click('[data-test-button="members-actions"]'); - expect(find('[data-test-button="delete-selected"]')).to.exist; - - // Apply a second filter - await click('[data-test-button="members-filter-actions"]'); - await click('[data-test-button="add-members-filter"]'); - await fillIn('[data-test-members-filter="1"] [data-test-select="members-filter"]', `newsletters.slug:${newsletterTwo.slug}`); - await click(`[data-test-button="members-apply-filter"]`); - - expect(findAll('[data-test-member]').length).to.equal(2); - expect(currentURL()).to.equal(`/members?filter=(newsletters.slug%3A${newsletterOne.slug}%2Bemail_disabled%3A0)%2B(newsletters.slug%3A${newsletterTwo.slug}%2Bemail_disabled%3A0)`); - - // Bulk deletion is not permitted anymore - await click('[data-test-button="members-actions"]'); - expect(find('[data-test-button="delete-selected"]')).to.not.exist; - }); - it('can bulk delete members if a non-Stripe subscription filter is in use (member tier, status)', async function () { const tier = this.server.create('tier', {id: 'qwerty123456789'}); this.server.createList('member', 2, {status: 'free'}); diff --git a/ghost/bookshelf-repository/package.json b/ghost/bookshelf-repository/package.json index 33db7ccf47..bbf859b272 100644 --- a/ghost/bookshelf-repository/package.json +++ b/ghost/bookshelf-repository/package.json @@ -23,7 +23,7 @@ "c8": "7.14.0", "mocha": "10.2.0", "sinon": "15.2.0", - "@tryghost/nql": "0.12.4" + "@tryghost/nql": "0.12.5" }, "dependencies": { "@tryghost/mongo-utils": "0.6.2", diff --git a/ghost/collections/package.json b/ghost/collections/package.json index f26123e4ea..31db0d121a 100644 --- a/ghost/collections/package.json +++ b/ghost/collections/package.json @@ -30,7 +30,7 @@ "@tryghost/errors": "1.3.5", "@tryghost/in-memory-repository": "0.0.0", "@tryghost/logging": "2.4.18", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/nql-filter-expansions": "0.0.0", "@tryghost/post-events": "0.0.0", "@tryghost/tpl": "0.1.32", diff --git a/ghost/core/package.json b/ghost/core/package.json index cc28088d82..2fb1e75e4f 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -73,7 +73,7 @@ "@tryghost/api-framework": "0.0.0", "@tryghost/api-version-compatibility-service": "0.0.0", "@tryghost/audience-feedback": "0.0.0", - "@tryghost/bookshelf-plugins": "0.6.23", + "@tryghost/bookshelf-plugins": "0.6.24", "@tryghost/bootstrap-socket": "0.0.0", "@tryghost/collections": "0.0.0", "@tryghost/color-utils": "0.2.2", @@ -141,7 +141,7 @@ "@tryghost/mw-version-match": "0.0.0", "@tryghost/mw-vhost": "0.0.0", "@tryghost/nodemailer": "0.3.45", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/oembed-service": "0.0.0", "@tryghost/package-json": "0.0.0", "@tryghost/post-revisions": "0.0.0", @@ -193,7 +193,7 @@ "ghost-storage-base": "1.0.0", "glob": "8.1.0", "got": "11.8.6", - "gscan": "4.43.3", + "gscan": "4.43.4", "human-number": "2.0.4", "image-size": "1.1.1", "intl": "1.2.5", diff --git a/ghost/custom-theme-settings-service/package.json b/ghost/custom-theme-settings-service/package.json index ebfcb42896..52dcb2dda5 100644 --- a/ghost/custom-theme-settings-service/package.json +++ b/ghost/custom-theme-settings-service/package.json @@ -27,7 +27,7 @@ "dependencies": { "@tryghost/debug": "0.1.32", "@tryghost/errors": "1.3.5", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/tpl": "0.1.32", "lodash": "4.17.21" } diff --git a/ghost/in-memory-repository/package.json b/ghost/in-memory-repository/package.json index d7a3e0efb9..b6c2e1898a 100644 --- a/ghost/in-memory-repository/package.json +++ b/ghost/in-memory-repository/package.json @@ -25,6 +25,6 @@ "sinon": "15.2.0" }, "dependencies": { - "@tryghost/nql": "0.12.4" + "@tryghost/nql": "0.12.5" } } diff --git a/ghost/link-tracking/package.json b/ghost/link-tracking/package.json index 80798304fc..fc3a7019ca 100644 --- a/ghost/link-tracking/package.json +++ b/ghost/link-tracking/package.json @@ -26,7 +26,7 @@ "dependencies": { "@tryghost/errors": "1.3.5", "@tryghost/link-redirects": "0.0.0", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/tpl": "0.1.32", "bson-objectid": "2.0.4", "lodash": "4.17.21", diff --git a/ghost/members-api/package.json b/ghost/members-api/package.json index 42854840b6..871946d299 100644 --- a/ghost/members-api/package.json +++ b/ghost/members-api/package.json @@ -36,7 +36,7 @@ "@tryghost/magic-link": "0.0.0", "@tryghost/member-events": "0.0.0", "@tryghost/members-payments": "0.0.0", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/tpl": "0.1.32", "@tryghost/validator": "0.2.14", "@types/jsonwebtoken": "9.0.6", diff --git a/ghost/posts-service/package.json b/ghost/posts-service/package.json index 832dfd585b..033fe1287e 100644 --- a/ghost/posts-service/package.json +++ b/ghost/posts-service/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@tryghost/errors": "1.3.5", - "@tryghost/nql": "0.12.4", + "@tryghost/nql": "0.12.5", "@tryghost/post-events": "0.0.0", "@tryghost/tpl": "0.1.32", "bson-objectid": "2.0.4" diff --git a/yarn.lock b/yarn.lock index f295ef38cc..c900c216fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7456,14 +7456,14 @@ "@tryghost/debug" "^0.1.33" lodash "^4.17.21" -"@tryghost/bookshelf-filter@^0.5.19": - version "0.5.19" - resolved "https://registry.yarnpkg.com/@tryghost/bookshelf-filter/-/bookshelf-filter-0.5.19.tgz#bc43e7823462762b8599a7ac09e82cc281d36301" - integrity sha512-q8hF2+Rt35D0v+VIWPqkQlLAPsF5R5R4Mq2q1GhQ+n+OcYerlX7vFR9FKlGfrVeBg9HsLUBTNlZacm407HaLHA== +"@tryghost/bookshelf-filter@^0.5.20": + version "0.5.20" + resolved "https://registry.yarnpkg.com/@tryghost/bookshelf-filter/-/bookshelf-filter-0.5.20.tgz#e1c7a99314305178488dd8024b1b66c4a492caae" + integrity sha512-gPdss759jRIzI+o8U3wPCAL0qBB0DmLlsT8TPicF33kN4d/MSx5ab4bUtKqH/5AaYaSBQvPhZEEv5SZUI3Ztpw== dependencies: "@tryghost/debug" "^0.1.33" "@tryghost/errors" "^1.3.6" - "@tryghost/nql" "^0.12.4" + "@tryghost/nql" "0.12.5" "@tryghost/tpl" "^0.1.33" "@tryghost/bookshelf-has-posts@^0.1.33": @@ -7498,15 +7498,15 @@ "@tryghost/tpl" "^0.1.33" lodash "^4.17.21" -"@tryghost/bookshelf-plugins@0.6.23": - version "0.6.23" - resolved "https://registry.yarnpkg.com/@tryghost/bookshelf-plugins/-/bookshelf-plugins-0.6.23.tgz#3b17f49d397a618911065593c8aa044881491853" - integrity sha512-Muuk8J9t3Dv630FpT1cqhan6J6GGIXUjZ7r25IcymQPideUbAvZXt0jEXWN7jpB1pq3+MdbRJSOmw+KrVlWbtg== +"@tryghost/bookshelf-plugins@0.6.24": + version "0.6.24" + resolved "https://registry.yarnpkg.com/@tryghost/bookshelf-plugins/-/bookshelf-plugins-0.6.24.tgz#f44c783e11da55fab95d8a5064a96ae58360aede" + integrity sha512-tX35hQDTR7dXyY2Nd8t88hscVhRTe27okwxvIM9sR+QzJQ6yu7RUhQCqpdlRPtfzMwbF3vRxxaEAAaqsLZ4b6Q== dependencies: "@tryghost/bookshelf-collision" "^0.1.46" "@tryghost/bookshelf-custom-query" "^0.1.28" "@tryghost/bookshelf-eager-load" "^0.1.32" - "@tryghost/bookshelf-filter" "^0.5.19" + "@tryghost/bookshelf-filter" "^0.5.20" "@tryghost/bookshelf-has-posts" "^0.1.33" "@tryghost/bookshelf-include-count" "^0.3.16" "@tryghost/bookshelf-order" "^0.1.28" @@ -7907,10 +7907,10 @@ dependencies: date-fns "^2.28.0" -"@tryghost/nql@0.12.4", "@tryghost/nql@^0.12.0", "@tryghost/nql@^0.12.4": - version "0.12.4" - resolved "https://registry.yarnpkg.com/@tryghost/nql/-/nql-0.12.4.tgz#ae482a78faa5cdd23da0d440b8248b2c942cfc6c" - integrity sha512-t1qTtFwFETjNe2CEZneLWzfDeLO3eQQMhYtyC/LvanOtpr/dn5gn5HCBCQ/MYi+nLwXeYlUMy7Lcjj1V3ToN5Q== +"@tryghost/nql@0.12.5", "@tryghost/nql@^0.12.5": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@tryghost/nql/-/nql-0.12.5.tgz#dc4531e26af06fd40c3b182295a480923cc44591" + integrity sha512-vc7IBsmYLb7zszLTFxGcDobkUKQ3cBKTEq3P71OGt7ranVI3KD1Du5Pq90eowQflT61DTy5eU7U9mltXOGvEkw== dependencies: "@tryghost/mongo-knex" "^0.9.1" "@tryghost/mongo-utils" "^0.6.2" @@ -18855,17 +18855,17 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== -gscan@4.43.3: - version "4.43.3" - resolved "https://registry.yarnpkg.com/gscan/-/gscan-4.43.3.tgz#2d04863569ff3eec72d941eb84afd0cfd94ee56c" - integrity sha512-ReFWSD4RCRtfu8zchUXiYrIvXq6oFwCsBRrbMUFLB4QAnHtIwyYAypGXFWrNAhVbs2F1gSZ6a7kyCVF0di/wlA== +gscan@4.43.4: + version "4.43.4" + resolved "https://registry.yarnpkg.com/gscan/-/gscan-4.43.4.tgz#f5ec47539d4ceeb57b853f4a1e67956214436c15" + integrity sha512-/oELLApcxX/C9IeYjljxOOi2jcGVeIVGttDo5ipkQOLcb1xUsUm4TrMLYWpmw//KhZwpwgP//12vRDJHDvR7lA== dependencies: "@sentry/node" "^7.73.0" "@tryghost/config" "^0.2.18" "@tryghost/debug" "^0.1.26" "@tryghost/errors" "^1.2.26" "@tryghost/logging" "^2.4.7" - "@tryghost/nql" "^0.12.0" + "@tryghost/nql" "^0.12.5" "@tryghost/pretty-cli" "^1.2.38" "@tryghost/server" "^0.1.37" "@tryghost/zip" "^1.1.42"