no issue
- left `mobiledoc` as the only default format added in the post/page input serializers for now to minimize API/test churn during these early stages of lexical development
- tested that the `lexical` field is not returned by default but can be requested via `?formats=lexical`
no issue
- similar to the `mobiledoc` field, the Content API should not return the source `lexical` field if requested via `?formats=`
- renamed `removeMobiledocFormat()` to `removeSourceFormats()` to better match it's behaviour
closes https://github.com/TryGhost/Team/issues/1884
- adds `post.lexical` ready for use by the lexical-powered editor re-write
- fulfils the same purpose as `posts.mobiledoc` so uses the same field properties
- added `lexical` to allowed formats in Post model so it won't be included by default in API responses meaning tests/snapshots don't need updating at present
closes https://github.com/TryGhost/Team/issues/1864
refs https://github.com/TryGhost/Team/issues/1881
- triggers free member email alert via event dispatch from member create method
- passes subscription/stripe data to member creation for paid members so free member alert can be ignored for them
- moves subscription created event being called from webhook controller to `linkSubscription`, allows creating subscription events for all new subscriptions instead of ones just via webhooks
refs https://github.com/TryGhost/Team/issues/1865
- refactors staff service to listen to member and subscription events
- triggers email alerts based on events instead of directly calling the service
- removes staff service dependency for members api
no issue
- Bumped into these tests when doing cleanup in the notifications service. Having full snapshot of requests is useful to have as a sanity check, so migrated this test suite quickly.
closes https://github.com/TryGhost/Team/issues/1772
- The user facing side of comments recently replaced `bio` with `expertise`.
- To remain consistent we replaced all the references of `bio` with `expertise` throughout the codebase.
- This includes a database column name changing migration, within the `members` table.
- Bumped up the comments-ui version to a new minor (0.10.x) as its a breaking change.
fixes https://github.com/TryGhost/Toolbox/issues/356
- this feature allows site Administrators to view a history log of staff
actions on their site so they can audit when and by whom that something happened
- this commit promotes the History log to GA
- this prevents the referrer/referer header being sent for requests that go to external domains
- this in turn prevents preview URLs from appearing in the analytics of sites that are linked to and clicked on from previews
- otherwise, preview URLs can be leaked to the owners of the linked and clicked sites
refs https://github.com/TryGhost/Team/issues/1795
- Snapshots help us detect unexpected changes in the `<head>` of all sites (e.g., newly introduced script tags)
- Added ghost_head tests for comment count helper
refs https://github.com/TryGhost/Team/issues/1871
This commit adds a test to the serialize method of `post-emaiserializer`. It checks whether the generated email HTML is valid and standard HTML5 and that all properties are escaped.
To do this validation, I depend on the new `html-validate` dev dependency. Just parsing the HTML with a HTML parser is not enough to guarantee that the HTML is okay.
Apart from that this fixes:
- Removed the sanitizeHTML method and replaced it with normal HTML escaping. We don't want to allow any HTML in the escaped fields. Whereas `sanitizeHTML` still allows valid HTML, but we don't want that and want the same behaviour as on the site. E.g., a post with a title `All your need to know about the <br /> tag` should actually render the same title and non-html content, being `All your need to know about the <br /> tag`
- The file, nft and audio card didn't (always) escape the injected HTML fields (new version @tryghost/kg-default-cards)
- `@tryghost/string` is bumped because it contains the new escapeHtml method
refs https://github.com/TryGhost/Ghost/pull/15375
- we currently pass all properties for the `tags` property of a
`page`/`post` body down further into Ghost, which is causing issues
because it's handling properties it doesn't expect
- this is showing up because it's triggering save history events for
tags when a post is edited
- this commit introduces a clean util which has an allowlist of
properties allows on tag relations
- this list was taken from the schema: 128f8fb006/packages/admin-api-schema/lib/schemas/posts.json (L214-L227)
refs https://github.com/TryGhost/Team/issues/1879
OpenSea updated their URL format for NFTs after adding support for Solana
which broke our regex, this updates to support the new format.
fixes https://github.com/TryGhost/Team/issues/1861
- Moved like and unlike endpoint handling to comments service and controller
- Moved small part of report logic to comments controller
- Added proper 401 authentication error when not authenticated as member
refs https://github.com/TryGhost/Toolbox/issues/384
- Existing adapter config was based on the notion there can only be one configuration per one adapter class. With adapter cache now allowing instantiating multiple adapter instances with the same base class it opened up a possibility to have shared configuration for a base class and then extend/override it in "feature" configurations (see tests in this commit for specific examples)
refs https://github.com/TryGhost/Team/issues/1875
- due to an misbehavior in our model layer, when `tiers` is set on a Post, it'll
trigger a save of the Tier, and this produces an extra event in the
`actions` table
- mapping the Tier(s) to just the ID prevents bookshelf-relations from
editing the Tier and thus prevents the extra event
- also fixed tests which were implicitly assuming supplying a slug to a
post would create the product
fixes https://github.com/TryGhost/Team/issues/1855
fixes https://github.com/TryGhost/Team/issues/1866
This commit moves all duplicate methods to get the support email address to a single location. Also methods to get the default email domain are moved.
For the location, I initially wanted to put it at the settings service. But that service doesn't feel like the right place. Instead I created a new settings helpers service. This service takes the settingsCache, urlUtils and config and calculates some special 'calculated' settings based on those:
- Support email methods
- Stripe (active) keys / stripe connected (also removed some duplicate code that calculated the keys in a couple of places)
- All the calculated settings are moved to the settings helpers
I'm not 100% confident in whether this is the right place to put the helpers. Suggestions are welcome.
fixes https://github.com/TryGhost/Team/issues/1870
Disables email sanitization that was enabled earlier because this bug is more important and urgent.
The recently introduced email sanitzation removes HTML comments from the post html.
- This breaks the email paid preview, because it depends on the `<!--members-only-->` comment.
- Breaks the Outlook comments `<!--[if !mso !vml]-->`
This commit reverts this change.
closes: https://github.com/TryGhost/Toolbox/issues/342
refs: 032a26f9f3
refs: 588c9d04e8
- Now that the old `users:no-owner` (now named 'users') is working correctly :)
- Was able to add loginAs[Role] methods for each staff role, so that it's possible to execute tests as that user and check permissions
- Refactored the email preview tests to use the new e2e framework and these methods, as an example
- This fixture is the main user fixture you'd want to use when testing staff roles
- At the moment it has a weird name that makes it less likely people will use it
- A tiny step in trying to make our fixture system make a tiny bit more sense
- This fixture would only work if the roles were inserted by the fixture system
- In most cases, this fixture was adding users without their associated roles
- Now we assume the roles exist already, and that we need to map users to each role
- This will allow us to more easily test user roles in e2e tests
refs https://github.com/TryGhost/Team/issues/1771
We don't have access to `req.brute.reset` due to the way the flow
works, we have one endpoint which sends an email with a magic link,
and another route which handles the login. We don't want to apply
brute force protection to both because our rate limiting is designed
for API requests not web page visits (which is how login is handled).
Because of this we require access to the underlying ExpressBrute
instance exposed by the spam-protection module, so that we can
perform the reset.
refs https://github.com/TryGhost/Team/issues/1074
Rather than relying on the global block to stop malicious actors from
enumerating email addresses to determine who is and isn't a user, we
want our user login brute force protection to be on an IP basis,
rather than tied to the username.
refs https://github.com/TryGhost/Toolbox/issues/389
- The e2e test suite log was full of ERR_NOCK_NO_MATCH warnings when the logging level was set to "warn". The cause of this warning was legit duplicated webhook trigger processing on test environment. Gah!
- The source of duplicate webhook processing was duplication of event handlers. Event handlers were registered multiple times for same event because of the singleton nature of the "common/events" module - it remains the same instance and is not cleaned up between reboots. The deeper issue of events module initialization should be solved separately, this slightly hacky approach fixes the problem now and highlights it to be tackled in the future.
refs https://github.com/TryGhost/Team/issues/1074
Rather than relying on the global block to stop malicious actors from
enumerating email addresses to determine who is and isn't a user, we
want our user login brute force protection to be on an IP basis,
rather than tied to the username.
refs https://github.com/TryGhost/Toolbox/issues/389
- if we enable warning logs in E2E tests, we get a bunch of error
messages saying `ERROR Unhandled rejection: aborted` coming from the
SQLite DB reset code
- specifically, it's coming from the line that resets the DB by copying
the file
- this line was initially added because we would see random SQLite
"malformed database" errors
- I have a feeling that was due to something else, but I can't be sure
- I'm also not sure how else we should shut the DB connection, as this
is the recommended way but it throws an unhandled rejection
- this commit is a bit of a gamble because I'm not actually sure what
was causing the problem, but it gets rid of the errors locally and
doesn't regress on the random failures
fixes https://github.com/TryGhost/Team/issues/1860
**Problem:**
Members were not able to comment on a post that was only visible for members with a specific tier.
**Causes:**
Content gating was done on models with missing relations.
- The products relation was not loaded on the member when doing content gating
- The tiers relation was not loaded on the post when doing content gating
**Tests:**
- Added for tier-only posts
- Added for paid-only commenting
fixes https://github.com/TryGhost/Team/issues/1859
**Problem:**
When for some reason a member has an active subscription (or legacy comped subscription) for product A, and a comped subscription for product B. You cannot remove comped subscription B.
**Fixed by:**
Updating the API to allow more flexible product changes on members.
- Allow the removal of (comped) products on a member, as long as that product doesn't have a related subscription
- (still) allow the addition of comped products to a member, as long as that member doesn't have other active subscriptions. This matches the existing behaviour, but now this is only checked for added products.
- Includes tests for these edge cases
fixes https://github.com/TryGhost/Team/issues/1860
**Problem:**
Members were not able to comment on a post that was only visible for members with a specific tier.
**Causes:**
Content gating was done on models with missing relations.
- The products relation was not loaded on the member when doing content gating
- The tiers relation was not loaded on the post when doing content gating
**Tests:**
- Added for tier-only posts
- Added for paid-only commenting
fixes https://github.com/TryGhost/Team/issues/1859
**Problem:**
When for some reason a member has an active subscription (or legacy comped subscription) for product A, and a comped subscription for product B. You cannot remove comped subscription B.
**Fixed by:**
Updating the API to allow more flexible product changes on members.
- Allow the removal of (comped) products on a member, as long as that product doesn't have a related subscription
- (still) allow the addition of comped products to a member, as long as that member doesn't have other active subscriptions. This matches the existing behaviour, but now this is only checked for added products.
- Includes tests for these edge cases
fixes https://github.com/TryGhost/Team/issues/1679
These endpoints are safe to be removed, as they are only used by the admin app and usage has been removed over there. It is very unlikely that this endpoint has been used in a third party integration (in which case they will get a notification email).
no issue
- Return was missing for `res.end` if an invalid subscription_id was passed
- Added explicit `text/plain` `Content-Type` headers to error messages to avoid MIME sniffing
Signed-off-by: Elijah Conners <business@elijahpepe.com>
Co-authored-by: Simon Backx <simon@ghost.org>
In case there is an issue with the filtering of items in our client
side attribution script, we also check for and remove out of date
items here. This ensures that we do not erroneously attribute signups
or conversions to webpages from more than 24h ago.
refs TryGhost/Team#1826
- adds a method on user model which fetches all eligible users for a type of email alert
- restricts users to active `Owner` and `Administrators` with setting turned on
closes: https://github.com/TryGhost/Team/issues/1732
- adds a theme helper which outputs a working search button with a standard icon
- the icon adopts whatever the current color is from css, and has a set of default styles
- styles can be overridden with !important or the data attribute
- alternatively, any element in a theme may be turned into a search button by adding data-ghost-search
- this is meant to be a simple tool for non-theme-developers to easily add a search icon to their themes in a way that doesn't require css or html knowledge
refs: 203c8036fa
refs: 1fadbacdec
refs: 22fd7f289c
- There is something seriously weird about how content-length changes...
- It's different on CI to local sometimes...
- This particular test should not change IMO
refs https://github.com/TryGhost/Team/issues/1833
refs https://github.com/TryGhost/Team/issues/1834
We've added the attribution property to subscription and signup events when the
flag is enabled. The attributions resource is fetched by creating multiple relations
on the model, rather than polymorphic as we ran into issues with that as they can't
be nullable/optional.
The parse-member-event structure has been updated to make it easier to work with,
specifically `getObject` is only used when the event is clickable, and there is now a
join property which makes it easier to join the action and the object.
refs https://github.com/TryGhost/Team/issues/1833
refs https://github.com/TryGhost/Team/issues/1834
We've added the attribution property to subscription and signup events when the
flag is enabled. The attributions resource is fetched by creating multiple relations
on the model, rather than polymorphic as we ran into issues with that as they can't
be nullable/optional.
The parse-member-event structure has been updated to make it easier to work with,
specifically `getObject` is only used when the event is clickable, and there is now a
join property which makes it easier to join the action and the object.
refs: https://github.com/TryGhost/Ghost/issues/14882
- I found a common pattern where catch predicates were being used to catch non-existent models in destroy methods, and sometimes elsewhere in the API endpoints
- The use of predicates is deprecated, and we're working to remove them from everywhere, so that we can remove bluebird
- In order to still handle these errors correctly, we needed a small change to mw-error-handler so that it can detect EmptyResponse errors from bookshelf, as well as 404s
Note: there is a small change as a result of this - the context on these errors now says "Resource not found" instead of "{ModelName} not found".
- I think this is acceptable for now, as we will be reviewing these errors in more depth later. It's quite easy to make changes, we just have to decide what with proper design input
refs https://github.com/TryGhost/Team/issues/1825
- adds 3 new columns to users table for storing email alert preferences for member signups/cancellation
- adds column for new member signup alert
- adds column for paid subscription started alert
- adds column for paid subscription canceled alert
- Updated default fixtures and tests for new columns
refs https://github.com/TryGhost/Toolbox/issues/356
- we have a very crude version of this before but it just wasn't
maintainable
- one of the first things I did here was to add `include=resource` on
the API call, so it returns the fields we need without extra API
requests
- after we have the id/slug, I could build a route and model array
dynamically, or return null if we can't redirect to the object (it
doesn't exist)
- copied over and rewrote the deletion test from the legacy file
- added a new test that checks that we get a 404 when attempting to delete an unknown post
- this is a guard to protect and futureproof the API whilst we do refactoring to improve 404 handling from bookshelf
- in turn this is aimed at helping to get rid of a bunch of catch predicates from the API
- I want to start rewriting the post tests using the new e2e framework, but it's quite a big task
- For now I have renamed the existing file, and will use the correct file name for writing modern versions of tests
- Note: I have a specific test that I'd like to add which is far easier to write in the new framework
- This change should facilitate moving forward more with the new framework
refs https://github.com/TryGhost/Toolbox/issues/356
- in order to show data that we might not necessarily still have around
(ie. when you delete a post, you might want the title), we're going to
start utilizing the `context` column
- right now, we store the `primary_name` for deleted events, and we also
store the `setting` `key` and `group` so we can reference it in the
audit log
no issue
- The site locale should be exposed within the public site config in order to handle i18n in third party apps
- Added the locale to Explore service to simplify fetching it when submitting a new site
fixes https://github.com/TryGhost/Team/issues/1829
- Remove the subdirectories when creating the Attribution instances
- URLs are now always stored relative to the subdirectory instead of the root directory (makes changing the subdirectory easier)
- Fixed returning absolute urls
- Added tests
- this endpoint returns the Ghost version, of which the minor just hit
double digits
- because of this, the content-length size changed, and the snapshot was
incorrect
- we've previously allowed overrides for the content-length to be any number (see
1fadbacdec)
- this commit allows the header to be any number so it doesn't fail when
the Ghost version is incremented
closes: https://github.com/TryGhost/Ghost/issues/15252
- comments are deleted when posts are deleted. Without cascade delete on parent_id, replies cannot be deleted
- this change means that deleting a post will delete all comments and replies without error
refs: https://github.com/TryGhost/Ghost/issues/15252
- all columns with a foreign key (references prop) must have a deletion strategy
- we just found a bug with this in the comments table - see referenced issue
- this fix adjusts the schema and migration for this change before its released so we don't have to write a horrible migration later
refs https://github.com/TryGhost/Team/issues/1727
- if feature flag is enabled, handles storing expiry date on complimentary subscriptions in `expiry_at` column of `members_products`
- updates the expiry value on both member edit or add with tiers
- expiry is passed as `expiry_at` in `tiers` list of a member
- includes `expiry_at` on tiers data of a member when flag is enabled
refs: 22fd7f289c
- in the mentioned commit I changed the tests so that we don't need to update snapshots for every labs flag change
- this commit does the same for content-length which didn't get picked up locally, but does on CI for some reason
- the goal is to allow the team to add and remove flags without needing to update a random snapshot
refs https://github.com/TryGhost/Team/issues/1822
Exposing the values through the API is restricted behind the alpha flag.
We're exposing the values by default when the flag is enabled for now,
but can reconsider that later.
refs https://github.com/TryGhost/Team/issues/1808
refs https://github.com/TryGhost/Team/issues/1809
refs https://github.com/TryGhost/Team/issues/1820
refs https://github.com/TryGhost/Team/issues/1814
### Changes in `member-events` package
- Added MemberCreatedEvent (event, not model)
- Added SubscriptionCreatedEvent (event, not model)
### Added `member-attribution` package (new)
- Added the AttributionBuilder class which is able to convert a url history to an attribution object (exposed as getAttribution on the service itself, which handles the dependencies)
```
[{
"path": "/",
"time": 123
}]
```
to
```
{
"url": "/",
"id": null,
"type": "url"
}
```
- event handler listens for MemberCreatedEvent and SubscriptionCreatedEvent and creates the corresponding models in the database.
### Changes in `members-api` package
- Added urlHistory to `sendMagicLink` endpoint body + convert the urlHistory to an attribution object that is stored in the tokenData of the magic link (sent by Portal in this PR: https://github.com/TryGhost/Portal/pull/256).
- Added urlHistory to `createCheckoutSession` endpoint + convert the urlHistory to attribution keys that are saved in the Stripe Session metadata (sent by Portal in this PR: https://github.com/TryGhost/Portal/pull/256).
- Added attribution data property to member repository's create method (when a member is created)
- Dispatch MemberCreatedEvent with attribution
### Changes in `members-stripe-service` package (`ghost/stripe`)
- Dispatch SubscriptionCreatedEvent in WebhookController on subscription checkout (with attribution from session metadata)
refs https://github.com/TryGhost/Toolbox/issues/364
refs 147ec91162
- This looks like a subtle bug that has gone unnoticed for years. Have checked if we rely on the logic anywhere (mostly used in image-dimensions frontend helper) - we don't access the "url" directly.
- There is no reasoning attached behind why the cached size was stored as a url (see refed commit)
- WHY is this even being fixed? Caches can store anything... does not mean we should! Inconsistent data becomes a real PITA if the cache is persisted and is hard to repopulate (e.g. to migrate the cached data format).
refs https://github.com/TryGhost/Toolbox/issues/364
- The "new Map()" cache was a "hidden cache" that did not follow any specific pattern. Following the cache adapter pattern here makes it possible swapping out the cache for alternative implementations - e.g. Redis storage
refs https://github.com/TryGhost/Toolbox/issues/364
- The InMemoryCache is an implementation of the cache adapter interface and allows to test cache in the works which is "close to the real world". Being able to do so in tests for image sizes cache manager proves we can use other cache adapters such as Redis based ones.
refs https://github.com/TryGhost/Toolbox/issues/364
- Doing the `.catch(errors.NotFoundError...` was throwing another error as this syntax did not work with native promises. Checking `instanceof` works 100% and is way more explicit/readable way to handle this type of error differently
refs https://github.com/TryGhost/Toolbox/issues/364
- It was using an outdated syntax and relied on Bluebird depencency. Updated the syntax to async/await and dropped the Bluebird dependency.