Ghost
Ghost copied to clipboard
Unified members/paid-members enabled checks in Admin
no issue
- we had a confusing mix of manual underlying access setting checks, direct
settings.membersEnabled/paidMembersEnabledchecks, andmembersUtils.membersEnabled/paidMembersEnabledchecks- the
membersUtils.xEnabledchecks were originally in place to remove the repeated direct checks ofsettings.membersSignupAccess !== 'none'type checks that were spread around the codebase but the refactor to switch to those utils was never fully completed - we've later added API-level
membersEnabledandpaidMembersEnabledsettings whichmembersUtils.xEnabledchecks were switched to but we also started using the underlying settings directly in different parts of the codebase meaning we ended up with three different approaches - the confusion around and slightly different behaviour between these different methods meant our tests were also difficult to determine as setup helpers were doing different things that meant code paths using each different approach were not necessarily doing what was intended
- the
- unified to always use
settings.membersEnabledandsettings.paidMembersEnabled- removed the duplicate properties from
membersUtils - switched all uses of
membersUtilsand manual checks over tosettingschecks - updated test utils to update all impacted settings when enabling/disabling members
- removed the duplicate properties from
- fixed tests that were incorrectly testing against members disabled
- added missing
/api/admin/stats/mrr/mocked endpoint that was causing dashboard tests to fail now that we are correctly testing against the members enabled state
Walkthrough
The changes refactor the handling of member-related functionality throughout the Ghost admin interface. References to the membersUtils service have been removed and replaced with direct accesses to properties from the settings service. This affects conditional logic in multiple Handlebars templates, JavaScript components, controllers, helpers, models, and services related to the display of membership features, email analytics, and paid member configurations. Updates include revisions to service injections, computed properties, and conditional checks to reflect the use of new settings properties such as membersEnabled and paidMembersEnabled. Additional modifications update Mirage fixtures and endpoints, as well as test configurations, to load the corresponding settings properly.
Possibly related PRs
- TryGhost/Ghost#22172: Refactors involving the removal of the
membersUtilsservice and associated methods align closely with this PR’s adjustments to member-related functionality.
Suggested labels
migration, browser-tests
[!WARNING] There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
🔧 ESLint
If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
ghost/admin/app/components/gh-member-settings-form.js
Oops! Something went wrong! :(
ESLint: 8.57.1
Error: Failed to load parser '@babel/eslint-parser' declared in 'ghost/admin/.eslintrc.js': Cannot find module '@babel/eslint-parser' Require stack:
- /ghost/admin/.eslintrc.js at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15) at Function.resolve (node:internal/modules/helpers:145:19) at Object.resolve (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2346:46) at ConfigArrayFactory._loadParser (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3325:39) at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3099:43) at _normalizeObjectConfigDataBody.next (
) at ConfigArrayFactory._normalizeObjectConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3040:20) at _normalizeObjectConfigData.next ( ) at ConfigArrayFactory.loadInDirectory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2886:28) at CascadingConfigArrayFactory._loadConfigInAncestors (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3871:46) ghost/admin/app/components/gh-members-recipient-select.js
Oops! Something went wrong! :(
ESLint: 8.57.1
Error: Failed to load parser '@babel/eslint-parser' declared in 'ghost/admin/.eslintrc.js': Cannot find module '@babel/eslint-parser' Require stack:
- /ghost/admin/.eslintrc.js at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15) at Function.resolve (node:internal/modules/helpers:145:19) at Object.resolve (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2346:46) at ConfigArrayFactory._loadParser (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3325:39) at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3099:43) at _normalizeObjectConfigDataBody.next (
) at ConfigArrayFactory._normalizeObjectConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3040:20) at _normalizeObjectConfigData.next ( ) at ConfigArrayFactory.loadInDirectory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2886:28) at CascadingConfigArrayFactory._loadConfigInAncestors (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3871:46) ghost/admin/app/components/koenig-lexical-editor.js
Oops! Something went wrong! :(
ESLint: 8.57.1
Error: Failed to load parser '@babel/eslint-parser' declared in 'ghost/admin/.eslintrc.js': Cannot find module '@babel/eslint-parser' Require stack:
- /ghost/admin/.eslintrc.js at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15) at Function.resolve (node:internal/modules/helpers:145:19) at Object.resolve (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2346:46) at ConfigArrayFactory._loadParser (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3325:39) at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3099:43) at _normalizeObjectConfigDataBody.next (
) at ConfigArrayFactory._normalizeObjectConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3040:20) at _normalizeObjectConfigData.next ( ) at ConfigArrayFactory.loadInDirectory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2886:28) at CascadingConfigArrayFactory._loadConfigInAncestors (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3871:46)
- 16 others
📜 Recent review details
Configuration used: CodeRabbit UI Review profile: CHILL Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between d8a47162d4498f96be24bbf71e3b26a80a3dc959 and 92b3fef892057e15ae2bd7923641aa65c536c521.
📒 Files selected for processing (30)
ghost/admin/app/components/editor/modals/preview.hbs(1 hunks)ghost/admin/app/components/gh-member-details.hbs(1 hunks)ghost/admin/app/components/gh-member-settings-form.hbs(1 hunks)ghost/admin/app/components/gh-member-settings-form.js(1 hunks)ghost/admin/app/components/gh-members-no-members.hbs(1 hunks)ghost/admin/app/components/gh-members-recipient-select.js(2 hunks)ghost/admin/app/components/koenig-lexical-editor.js(2 hunks)ghost/admin/app/components/member-attribution/modals/all-sources.hbs(2 hunks)ghost/admin/app/components/member-attribution/modals/all-sources.js(1 hunks)ghost/admin/app/components/member-attribution/source-attribution-table.hbs(3 hunks)ghost/admin/app/components/member-attribution/source-attribution-table.js(1 hunks)ghost/admin/app/components/posts-list/context-menu.hbs(1 hunks)ghost/admin/app/components/posts-list/context-menu.js(1 hunks)ghost/admin/app/controllers/dashboard.js(1 hunks)ghost/admin/app/helpers/parse-member-event.js(2 hunks)ghost/admin/app/models/post.js(1 hunks)ghost/admin/app/services/dashboard-stats.js(1 hunks)ghost/admin/app/services/member-import-validator.js(0 hunks)ghost/admin/app/services/members-utils.js(2 hunks)ghost/admin/app/templates/dashboard.hbs(1 hunks)ghost/admin/app/templates/members.hbs(3 hunks)ghost/admin/app/utils/publish-options.js(1 hunks)ghost/admin/mirage/config/stats.js(1 hunks)ghost/admin/mirage/fixtures/settings.js(1 hunks)ghost/admin/mirage/routes-test.js(1 hunks)ghost/admin/tests/acceptance/content-test.js(5 hunks)ghost/admin/tests/acceptance/editor/post-email-preview-test.js(3 hunks)ghost/admin/tests/acceptance/members/filter-test.js(1 hunks)ghost/admin/tests/helpers/members.js(1 hunks)ghost/admin/tests/integration/services/member-import-validator-test.js(0 hunks)
💤 Files with no reviewable changes (2)
- ghost/admin/app/services/member-import-validator.js
- ghost/admin/tests/integration/services/member-import-validator-test.js
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Admin tests - Chrome
🔇 Additional comments (49)
ghost/admin/app/templates/dashboard.hbs (1)
105-105: Consistent property access pattern applied.This change replaces
membersUtils.membersInviteOnlywithsettings.membersInviteOnly, aligning with the PR objective to standardize member-related checks through the settings service directly.ghost/admin/app/controllers/dashboard.js (1)
24-24: Service dependency updated correctly.Replacing
membersUtilswithsettingsservice follows the PR objective to standardize member-related checks by accessing settings properties directly instead of going through the membersUtils service.ghost/admin/app/templates/members.hbs (3)
66-66: Standardized conditional check.Changed from checking
membersSignupAccessbeing "none" to usingsettings.membersEnableddirectly, which aligns with the PR objective to standardize member checks. This ensures consistent behavior across the codebase.
100-100: Standardized conditional check.Similar to the previous change, this replaces a check against
membersSignupAccesswith the more directsettings.membersEnabledproperty, maintaining consistent patterns throughout the application.
118-118: Standardized conditional check.The third instance of replacing a
membersSignupAccesscomparison with the cleanersettings.membersEnabledcheck maintains consistency for when the "New member" button should be displayed.ghost/admin/app/services/dashboard-stats.js (3)
364-364: Standardized service reference.Changed from
membersUtils.paidMembersEnabledtosettings.paidMembersEnabled, removing the dependency on the membersUtils service and using settings properties directly.
368-368: Standardized service reference in hasPaidTiers definition.Correctly updated the reference to use
settings.paidMembersEnabledinstead ofmembersUtils.paidMembersEnabled, maintaining consistent access patterns.
374-374: Standardized service reference in membersEnabled assignment.Changed from
membersUtils.isMembersEnabledtosettings.membersEnabled, completing the consistent pattern of using the settings service directly for all member-related properties.ghost/admin/app/services/members-utils.js (3)
19-19: Updated to use direct settings reference.The change correctly replaces the former use of
this.paidMembersEnabledgetter with direct access tothis.settings.paidMembersEnabled, aligning with the PR's objective to standardize member settings checks.
23-23: Updated to use direct settings reference.The change correctly replaces the use of
this.paidMembersEnabledgetter with direct access tothis.settings.paidMembersEnabled, consistent with the standardization approach.
49-49: Improved comment documentation.The comment has been correctly updated to guide developers to use
settings.paidMembersEnableddirectly, which is consistent with the code changes and helps prevent future confusion.ghost/admin/app/helpers/parse-member-event.js (2)
10-10: Added settings service injection.The change correctly adds the settings service injection to replace membersUtils.
296-296: Updated to use direct settings reference.The change correctly replaces the former use of
this.membersUtils.paidMembersEnabledwith direct access tothis.settings.paidMembersEnabled.ghost/admin/mirage/routes-test.js (1)
35-35:❓ Verification inconclusive
Enabled Mirage logging.
Changing logging to
truewill provide more visibility into Mirage routes during tests, which may be helpful for debugging the updated member settings behavior. However, this could potentially make test output more verbose.Consider whether this change is intentional or if it was meant to be temporary for debugging. If temporary, it should be reverted before merging.
🏁 Script executed:
#!/bin/bash # Check if there are any test files that might be affected by this change rg -l "mirage" --type js ghost/admin/testsLength of output: 1973
Verify Mirage logging intention in tests
- In
ghost/admin/mirage/routes-test.js(line 35), the propertythis.loggingis set totrue, which will enable verbose logging during tests.- The tests within
ghost/admin/tests/reference Mirage across multiple files, but there is no clear indication that verbose logging was meant to persist.- Please confirm whether enabling logging was an intentional permanent change to aid debugging, or if it was a temporary measure meant to be reverted before merging. If it was for temporary debugging only, kindly revert this change or add an inline comment clarifying the intent.
ghost/admin/app/components/posts-list/context-menu.hbs (1)
54-54: Updated to use direct settings reference.
The change correctly replaces the use of this.membersUtils.isMembersEnabled with direct access to this.settings.membersEnabled, which aligns with the PR's objective to standardize member settings checks.
ghost/admin/app/components/gh-member-settings-form.hbs (1)
82-82: Updated conditional logic to use settings service
The conditional check has been changed from using this.membersUtils.paidMembersEnabled to this.settings.paidMembersEnabled, which aligns with the PR objective of unifying member-related checks to use the settings service directly.
ghost/admin/app/components/member-attribution/modals/all-sources.js (1)
5-5: Service injection updated from membersUtils to settings
The component now injects the settings service instead of the membersUtils service, which aligns with the PR objective of unifying member-related checks to use settings directly.
ghost/admin/mirage/config/stats.js (1)
74-112: Added mock endpoint for MRR statistics
Added a new mock endpoint for /stats/mrr/ that provides structured test data for Monthly Recurring Revenue. This allows dashboard tests to work correctly with the updated member-enabled checks.
The mock data includes dates from 2025, which is appropriate for testing future projections, and provides a good variety of MRR values to test different scenarios.
ghost/admin/app/components/gh-member-settings-form.js (1)
26-26: Updated conditional logic to use settings service
The condition has been changed from if (!this.membersUtils.paidMembersEnabled) to if (!this.settings.paidMembersEnabled), aligning with the PR objective of unifying member-related checks to use settings directly.
ghost/admin/app/utils/publish-options.js (1)
124-127: Looks good - Unified membership checks.
The change from checking this.settings.membersSignupAccess === 'none' to !this.settings.membersEnabled aligns with the PR objective of standardizing member settings checks.
ghost/admin/app/components/member-attribution/source-attribution-table.hbs (1)
9-9: Properly standardized paid members settings checks.
All conditional checks now reference this.settings.paidMembersEnabled directly instead of using the membersUtils service, consistent with the PR's objective to unify member-related setting checks.
Also applies to: 11-11, 40-40, 72-72
ghost/admin/app/components/posts-list/context-menu.js (1)
68-68: Successfully migrated from membersUtils to settings service.
The change from @service membersUtils to @service settings supports the PR objective of removing duplicate properties from membersUtils and transitioning all checks to rely solely on the settings object.
ghost/admin/tests/acceptance/editor/post-email-preview-test.js (3)
4-4: Great addition of the disablePaidMembers helper.
Adding the helper and calling it appropriately ensures tests correctly simulate the disabled paid members state, aligning with the PR's goal of improving test accuracy.
Also applies to: 20-21
31-32: Improved test readability with descriptive assertion messages.
Adding descriptive messages ('newsletter select' and 'segment select') to the assertions makes test failures more informative and easier to debug.
Also applies to: 55-56
37-38: Properly configured test environment for accurate testing.
Including the call to disablePaidMembers(this.server) ensures the test environment correctly simulates the disabled paid members state, which is crucial for validating the expected behavior.
ghost/admin/mirage/fixtures/settings.js (1)
60-61: Good addition of member settings fixtures
These two new settings align with the PR objective of standardizing checks for member and paid member settings. Setting both to true by default is appropriate for test fixtures, as most tests will want to test with members enabled.
ghost/admin/app/components/member-attribution/source-attribution-table.js (1)
8-8:
✅ Verification successful
Service dependency change in line with PR objectives
This change replaces the membersUtils service with the settings service, aligning with the PR goal of standardizing member-related checks to use settings properties directly.
Run the following script to verify that all references to membersUtils.paidMembersEnabled have been replaced with settings.paidMembersEnabled in the template:
🏁 Script executed:
#!/bin/bash
# Check for any remaining references to membersUtils.paidMembersEnabled in the template
rg "membersUtils\.paidMembersEnabled" "ghost/admin/app/components/member-attribution/source-attribution-table.hbs" || echo "No references found - good!"
Length of output: 179
Service Dependency Update Verified
- The change in
ghost/admin/app/components/member-attribution/source-attribution-table.js(Line 8) to use@service settingsinstead ofmembersUtilsaligns with the PR goals. - The verification script confirms that all references to
membersUtils.paidMembersEnabledin the template have been successfully replaced withsettings.paidMembersEnabled.
ghost/admin/tests/acceptance/members/filter-test.js (1)
24-24:
✅ Verification successful
Added theme fixtures loading
This adds the loading of theme fixtures to the test setup. While not directly mentioned in the PR objectives, this might be necessary since the member settings are now standardized and tests may rely on proper theme fixtures.
Let's verify if there are any dependencies between themes and member settings that would make this addition necessary:
🏁 Script executed:
#!/bin/bash
# Look for any relationships between themes and member settings
rg -A 5 -B 5 "themes.*members" "ghost/admin" || echo "No direct relationship found in code"
Length of output: 127
Dependency Check Complete – Approved Theme Fixture Loading
The executed script did not reveal any direct dependencies between themes and member settings in the code. The addition of the fixture loading:
this.server.loadFixtures('themes');
remains valid for ensuring that tests have the necessary theme data for the standardized member settings. No further action is needed.
ghost/admin/app/components/editor/modals/preview.hbs (1)
12-12: Updated conditional check for email preview
This change replaces checking membersSignupAccess with checking settings.membersEnabled, which aligns with the PR objective of standardizing member-related checks to use settings properties directly.
The condition is now clearer and more straightforward: if members are enabled AND email recipients are not disabled, show the email preview option.
ghost/admin/app/components/member-attribution/modals/all-sources.hbs (2)
12-12: Correct usage of standardized settings check.
This change aligns with the PR objective to unify member-related checks through the settings service instead of using membersUtils.
32-32: Consistent approach to member settings check.
Good consistency with the earlier check in the same file, both now use this.settings.paidMembersEnabled.
ghost/admin/app/components/gh-members-no-members.hbs (1)
4-4: Simplified member-enabled check.
The change improves clarity by using the direct this.settings.membersEnabled property rather than checking against membership access values, which aligns with the PR objectives to standardize these checks.
ghost/admin/app/components/gh-member-details.hbs (1)
75-75: Standardized member-enabled check.
The condition has been simplified to use this.settings.membersEnabled directly while preserving the additional check for email recipients. This is consistent with the PR's objective to streamline member-related feature checks.
ghost/admin/tests/acceptance/content-test.js (4)
148-149: Added settings fixtures for editor tests.
Good addition of the settings fixtures loading, which is necessary since the editor tests now depend on member-related settings for the context menu functionality.
172-178: Updated context menu button expectations.
The test has been correctly updated to account for the added "Change access" button in the context menu, which is now visible based on the standardized member settings check.
339-346: Updated context menu button expectations for admin user.
The test expectations have been properly adjusted to include the additional "Change access" button in the admin context menu, keeping tests aligned with the implementation changes.
349-349: Updated button index for duplicate action.
The action index has been correctly updated to reflect the new position of the "Duplicate" button after the addition of the "Change access" button.
ghost/admin/app/components/gh-members-recipient-select.js (2)
12-12: Service dependency updated to match unified approach.
The component now relies on settings service instead of membersUtils, aligning with the PR objective to standardize member-related checks through the settings service.
43-43: Unified paid members check.
Changed from using this.membersUtils.isStripeEnabled to this.settings.paidMembersEnabled, ensuring consistent checks for paid members functionality throughout the application.
ghost/admin/app/components/koenig-lexical-editor.js (2)
285-285: Standardized paid members check.
Updated to use this.settings.paidMembersEnabled instead of this.membersUtils.paidMembersEnabled, ensuring consistency with other components that check for paid member availability.
449-449: Simplified members enabled check.
Changed from the indirect check this.settings.membersSignupAccess === 'all' to the more straightforward this.settings.membersEnabled, improving readability while maintaining the same functionality.
ghost/admin/app/models/post.js (4)
197-197: Standardized members enabled check in analytics.
Updated to use this.settings.membersEnabled instead of checking this.settings.membersSignupAccess !== 'none', making the code more readable and consistent.
205-205: Unified members enabled check in email click analytics.
Same change as in the email open analytics property, standardizing on this.settings.membersEnabled for consistency across the codebase.
211-215: Simplified invite-only members check.
Changed from using this.membersUtils.isMembersInviteOnly to directly checking !this.settings.membersInviteOnly, making the dependency hierarchy clearer and code more maintainable.
219-219: Standardized paid members check in analytics.
Using settings.paidMembersEnabled directly instead of going through membersUtils.paidMembersEnabled, creating a more consistent approach to checking paid member status.
ghost/admin/tests/helpers/members.js (4)
1-10: Enhanced test helper with parameterized members enabling.
The enableMembers function now accepts a boolean parameter to control both members_signup_access and the new members_enabled setting, making tests more flexible and aligned with the application's unified approach.
13-15: Simplified members disabling implementation.
Refactored to leverage the parameterized enableMembers function, making the code more DRY while maintaining the same functionality.
17-21: Enhanced paid members test helper with parameterization.
Similar to the enableMembers update, the paid members helper now accepts a boolean parameter for more flexible test setup.
23-25: Added missing paid members disabling helper.
Implemented the previously missing disablePaidMembers function to complement enablePaidMembers, completing the set of test utilities needed for proper test setup.
✨ Finishing Touches
- [ ] 📝 Generate Docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
I pushed a fix in commit <commit_id>, please review it.Generate unit testing code for this file.Open a follow-up GitHub issue for this discussion.
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. Examples:@coderabbitai generate unit testing code for this file.@coderabbitai modularize this function.
- PR comments: Tag
@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.@coderabbitai read src/utils.ts and generate unit testing code.@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.@coderabbitai help me debug CodeRabbit configuration file.
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.
CodeRabbit Commands (Invoked using PR comments)
@coderabbitai pauseto pause the reviews on a PR.@coderabbitai resumeto resume the paused reviews.@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository.@coderabbitai full reviewto do a full review from scratch and review all the files again.@coderabbitai summaryto regenerate the summary of the PR.@coderabbitai generate docstringsto generate docstrings for this PR.@coderabbitai resolveresolve all the CodeRabbit review comments.@coderabbitai planto trigger planning for file edits and PR creation.@coderabbitai configurationto show the current CodeRabbit configuration for the repository.@coderabbitai helpto get help.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
CodeRabbit Configuration File (.coderabbit.yaml)
- You can programmatically configure CodeRabbit by adding a
.coderabbit.yamlfile to the root of your repository. - Please see the configuration documentation for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation:
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
Documentation and Community
- Visit our Documentation for detailed information on how to use CodeRabbit.
- Join our Discord Community to get help, request features, and share feedback.
- Follow us on X/Twitter for updates and announcements.
Cleaning up older PRs 💅