refs https://github.com/TryGhost/Toolbox/issues/426
- we're going to need to support more complex combinations of dev
commands soon, with other packages optionally running and env
variables being altered
- this command pulls out a lot of the dev env scripting into a single
scripts
- also cleans up the use of grunt-shell so we can remove the dependency
fixes https://github.com/TryGhost/Team/issues/1952
Adds a new MemberLinkClickEvent event that is fired when a member clicks a link. This code has been added to the `linkClickRepository` because that is the only place that has access to the member model (and the event requires the id and current last seen at value). The LastSeenAtUpdater listens for this event and updates the timestamp if required.
closes https://github.com/TryGhost/Toolbox/issues/372
- The admin assets are served with a unique hash depending on the build with a year-long "max-age" value in the response cache-control header. The client browsers still do send 'If-None-Match' requests when there is a hard-refresh on the client side. There's no need for 'If-None-Match' requests though!
- With 'immutable' value in the cache-control header, the browser caches are treating responses as "hard-fresh" without sending redundant requests.
- For more about 'immutable' value read https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#immutable
refs https://github.com/TryGhost/Team/issues/1949
- bumps `@tryghost/kg-default-cards` which updates the rendered output for emails
- added `height: auto` style to the img element so clients don't render the image at the fixed image height retrieved from the `height="x"` attribute
closes https://github.com/TryGhost/Team/issues/1927
This expose the /links endpoint on the Admin API, which is filterable by Post ID.
Co-authored-by: Simon Backx <simon@ghost.org>
closes https://github.com/TryGhost/Team/issues/1942
- Added data fixtures for referrers
- Added new endpoint to fetch referrer stats for a given post: `/stats/referrers/posts/:id`
- Added new ReferrersStatsService, responsible for calculating referrer stats
refs TryGhost/Team#1931
- referrer source, medium and url will be stored in the events table along with rest of attribution data
- stores referrer information on two tables
- `members_created_events` for signups
- `members_subscription_created_events` for paid conversions
closes https://github.com/TryGhost/Team/issues/1933
- Added click_events to activity feed
- Added support for parsing click_events in the frontend
- Moved url parsing (transform ready) to model layer of LinkRedirect
- Moved `getEventTimeline` method to the top of the event repository
- Added description field to parsed events in the frontend (because we need a second line)
- Fixed: member email not returned in comment_event
- show both the status code and original error from mailgun
- clarify that the error is from mailgun
- swap from error to err as we're rolling out that pattern everywhere
Co-authored-by: Hannah Wolfe <github.erisds@gmail.com>
refs d5f03ec0b1
- underlying error message varies across node versions so the content-length can't be fixed
- applied any-content-length matcher to the right test this time
closes https://github.com/TryGhost/Team/issues/1916
closes https://github.com/TryGhost/Team/issues/1917
- Added database storage for link redirects and click events via repositories (hides away database layer) defined in the wrapper services
- Added LinkClickRepository to store click events to database
- Added LinkRedirectRepository to store link redirects to database
- Added PostLinkRepository to link LinkRedirects with posts
- Renamed link-replacement package to link-replacer, and made it dependency less (it only replaces links now, doesn't do anything else)
- The link-tracking service has a new `addTrackingToUrl` which returns a new URL that includes tracking. The new `addRedirectToUrl` method does the same but without tracking for now.
- MEGA service now uses the link-replacer to replace links in the emails using a combination of different services (member attribution + link-tracking service)
no issue
- setting the original error message to the `context` property means it's not completely lost and gives us a clue for debugging
- updated the lexical and mobiledoc validation errors to use the messages+tpl pattern
fixes https://github.com/TryGhost/Toolbox/issues/416
- this commit switches the default endpoint for our CDN-loaded assets to
a Ghost-specific jsDelivr one, with a shorter 10 min browser cache config, so
assets are refreshed quicker upon publishing
no issue
- bumped `@tryghost/url-utils` to get access to the new lexical transform utilities
- updated the Post model's `parse()` and `formatOnWrite()` methods to transform the `lexical` field contents when reading/writing to ensure any links in content point at the correct place with `site.url` config changes
refs TryGhost/Team#1907
- calculates final attribution source and medium using captured referrer information in history
- adds new referrer-translator that goes through available history and based to determine most valid referrer info
- includes referrer url, source and medium in the attribution data for storage
refs TryGhost/Team#1906
- captures referrer url and any source/medium param for referrer
- maintains history with latest referrer information when moving around pages
no issue
- The explore endpoint needs to expose the total amount of published posts
- To be more consistent, this PR creates a PostStats class which is exposed as `stats` method within the PostService; just like it's done with the MemberService
- Moved existing method to return the date of the most recently published post into the stats service
- Updated the explore service test to reflect the new return property
no issue
- added `PostRevsion` model
- duplicated `mobiledoc_revision` creation routine in Post model's onSaving hook to create `post_revision` when model's `lexical` field has changed
- updated `mobiledoc_revision` creation to skip when `lexical` field is populated
no issue
- adds `lexicalEditor` alpha labs flag and associated toggle in Admin
- when feature flag is enabled the new post/page routes will load the lexical editor instead of the mobiledoc editor
no issue
- initially this will perform the same function as `mobiledoc_revisions` but storing `lexical` instead of `mobiledoc`
- naming is intentionally generic ready for later expansions
closes https://github.com/TryGhost/Team/issues/1908
### Problem:
- We need tracking on the paywall links in each email. (we cannot ignore them because those buttons are probably gonna have a higher paid conversion attribution than others).
- Currently we only add the paywall HTML to an email when processing each batch. So if we batch an email to 1.000 recipients per 100, we'll generate the paywall HTML 10 times.
- We cannot replace links in `renderEmailForSegment` because that methods will get called multiple times. We don't want to have multiple redirect instances created for the same link in the same email.
### Solution:
- Move the generation of the paywall to the `serialize` method of the post email serializer.
- Surround the generated paywall with HTML-comments so we can remove it if required in `renderEmailForSegment` depending on the member segment we are sending the email to.
---
### Before:
**Serialize output:**
```html
<html>
<body>
<h1>Generated email header</h1>
<p>Generated text</p>
<div>
<!-- POST CONTENT START -->
<h1>Post title</h1>
<p>Content visible for all members</p>
<!--members-only-->
<p>Content visible for paid members only</p>
<!-- POST CONTENT END -->
</div>
</body>
</html>
```
To be modified later by `renderEmailForSegment`:
**Paid members (nothing changed):**
```html
<html>
<body>
<h1>Generated email header</h1>
<p>Generated text</p>
<div>
<!-- POST CONTENT START -->
<h1>Post title</h1>
<p>Content visible for all members</p>
<!--members-only-->
<p>Content visible for paid members only</p>
<!-- POST CONTENT END -->
</div>
</body>
</html>
```
**Free members (paywall _added_):**
```html
<html>
<body>
<h1>Generated email header</h1>
<p>Generated text</p>
<div>
<!-- POST CONTENT START -->
<h1>Post title</h1>
<p>Content visible for all members</p>
<h2>Generated paywall here</h2>
<a href="https://subscribe.com">Subscribe to read the full post</a>
<!-- POST CONTENT END -->
</div>
</body>
</html>
```
### After this change:
**Serialize output:**
```html
<html>
<body>
<h1>Generated email header</h1>
<p>Generated text</p>
<div>
<!-- POST CONTENT START -->
<h1>Post title</h1>
<p>Content visible for all members</p>
<!--members-only-->
<p>Content visible for paid members only</p>
<!-- PAYWALL -->
<h2>Generated paywall here</h2>
<a href="https://subscribe.com/?tracked">Subscribe to read the full post</a>
<!-- POST CONTENT END -->
</div>
</body>
</html>
```
To be modified later by `renderEmailForSegment`:
**Paid members (paywall removed):**
```html
<html>
<body>
<h1>Generated email header</h1>
<p>Generated text</p>
<div>
<!-- POST CONTENT START -->
<h1>Post title</h1>
<p>Content visible for all members</p>
<!--members-only-->
<p>Content visible for paid members only</p>
<!-- POST CONTENT END -->
</div>
</body>
</html>
```
**Free members (members-only content removed):**
```html
<html>
<body>
<h1>Generated email header</h1>
<p>Generated text</p>
<div>
<!-- POST CONTENT START -->
<h1>Post title</h1>
<p>Content visible for all members</p>
<!-- PAYWALL -->
<h2>Generated paywall here</h2>
<a href="https://subscribe.com/?tracked">Subscribe to read the full post</a>
<!-- POST CONTENT END -->
</div>
</body>
</html>
```
no issue
- added `@tryghost/kg-lexical-html-renderer` dependency
- added `lexical` lib following the same pattern as our `mobiledoc` lib
- updated the Post model's `onSaving` hook to generate the `html` value from `lexical` when present
fixes https://github.com/TryGhost/Team/issues/1909
- The feature image caption is already escaped on the frontend
- Doing it again in the backend breaks the possibility to add links to the caption
- I checked and the `feature_image_alt` is not escaped in the frontend.
fixes https://github.com/TryGhost/Team/issues/1909
- The feature image caption is already escaped on the frontend
- Doing it again in the backend breaks the possibility to add links to the caption
- I checked and the `feature_image_alt` is not escaped in the frontend.
fixes https://github.com/TryGhost/Team/issues/1900
refs https://github.com/TryGhost/Team/issues/1901
- Defaults to the same value as the current email_track_opens setting for existing installations, otherwise defaults to true
- Had to use a custom migration because the `addSetting` helper doesn't support using an existing setting as current value
- Added a minimal UI to change the setting, but this still needs some design magic 🪄✨
- Link replacement is disabled if `email_track_clicks` is disabled. In the future we might consider to still do parial additions, such as source attribution and maybe redirects (to discuss).
refs https://github.com/TryGhost/Team/issues/1899
- Added `addEmailAttributionToUrl` method to MemberAttributionService. This adds both the source attribution (`rel=newsletter`) and member attribution (`?attribution_id=123&attribution_type=post`) to a URL.
- The URLHistory can now contain a new sort of items: `{type: 'post', id: 'post-id', time: 123}`.
- Updated frontend script to read `?attribution_id=123&attribution_type=post` from the URL and add it to the URLHistory + clear it from the URL.
- Wired up some external dependencies to LinkReplacementService and added some dummy code.
- Increased test coverage of attribution service
- Moved all logic that removes the subdirectory from a URL to the UrlTranslator instead of the AttributionBuilder
- The UrlTranslator now parses a URLHistoryItem to an object that can be used to build an Attribution instance
- Excluded sites with different domain from member id and attribution tracking
We're going to be adding more redirection logic into Ghost and it's
going to get confusing if we have names this generic. This makes it
clear which feature this service is related to.
Ideally in the future we can combine all of these into one redirects
service, but for now we will be running a specific service per feature
https://github.com/TryGhost/Team/issues/1894
- The .m4a is an apple lossless format which comes up every so often. Adding support for this format seems easy enough than coming back to the topic of it's support once every 6 months ^_^
no issue
- fixed API returning "Invalid mobiledoc structure" errors when `mobiledoc:null` is sent in the payload alongside `lexical: '{...}'`
- updated Admin's `posts` and `pages` adapters to always add `?formats=mobiledoc,lexical` because the API doesn't return `lexical` by default
- added `lexical` attribute to Admin's Post model
- updated `lexical-editor` controller and related components to work with `lexical` always being a JSON string rather than a parsed object
- updated `<KoenigLexicalEditor>` to pass through the lexical state string as initial state and wired up the `onChange` prop
no issue
- bumped `@tryghost/admin-api-schema` to allow passthrough of the `lexical` property on post and page API endpoints
- prevented saving of blank document in the `mobiledoc` field if `lexical` is provided
- prevented API input containing both `mobiledoc` and `lexical` fields to avoid issues when both are present:
- not possible to know which content is latest/has precedence
- not possible to know which editor should be displayed in Admin
refs 9471384020
- previously added tests (any subsequent matcher updates) for browse endpoint were not using matchers that sufficiently covered the dynamic portions of the body
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
no issue
- updated default `editor.url` config to point at the `@tryghost/koenig-lexical` package
- uses unpkg.com for now for the faster cache clearing during active development
- adds `{version}` to the url and `editor.version` config to match the pattern in other apps
- updated `<KoenigLexicalEditor>` to use the new templated URL+version and the new global name used in the UMD build output
- commented out mobiledoc-editor related code in `<GhKoenigEditorLexical>` that could throw errors
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
- the migration in 5.14 renames the `bio` columns on `members` to `expertise`
- unfortunately, the Knex helper we were using does a lot of interesting
things with foreign keys that are slow on bigger MySQL clusters, and
that we don't need here
- this commit refactors the migration to use raw SQL if the DB is MySQL,
else we use the helper because SQLite SQL might be different here
- I've chosen to only run the renaming functionality if we're in the correct DB
state to do so (instead of erroring or trying to correct the state)
- the migration in 5.14 renames the `bio` columns on `members` to `expertise`
- unfortunately, the Knex helper we were using does a lot of interesting
things with foreign keys that are slow on bigger MySQL clusters, and
that we don't need here
- this commit refactors the migration to use raw SQL if the DB is MySQL,
else we use the helper because SQLite SQL might be different here
- I've chosen to only run the renaming functionality if we're in the correct DB
state to do so (instead of erroring or trying to correct the state)
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
- When we have todos related to deprecations, we should use @deprecated instead
- @deprecated notices should say when a feature was deprecated, not when it was removed
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.
no issue
- By bumping the version of adapter-base-cache I'm expecting `yarn` command to pick up this package. I suspect the failures on CI are due to some caching issue.
https://github.com/TryGhost/Toolbox/issues/364
- When the adapter base class lives deep inside Ghost's codebase it is pretty hard for other developers to extend it. With the goal of making Ghost easier to use and deploy by others, this kind of functionality should be as easy to extend as possible.
- The base adapters should live in the TryGhost/SDK repository. Next ones to move are Scheduling, SSO, and Storage base adapters.
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)
fixes https://github.com/TryGhost/Team/issues/1821
This change moves all the event storage logic to one new place: the event storage class in the MembersEventsService, which is initialised in a new members events service wrapper.
Apart from this, this includes some improvements:
- Removed DomainEvents from the constructor arguments to the subscribe method (to make it more clear where to subscribe to and decrease dependencies)
- LastSeenAtUpdater doesn't subscribe in the constructor any longer (removes unclear side effect)
- Moved LastSeenAtUpdater initialisation to new members events service wrapper
- Added missing tests to LastSeenAtUpdater to assure that the MembersEventsService package has 100% coverage.
closes https://github.com/TryGhost/Team/issues/1873
- bumps `@tryghost/kg-default-cards` which amends the product card rendering to output adjusted `width` and `height` attributes and a resized `src` attribute on the `<img>` element
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/Toolbox/issues/384
- Adapter cache was not able to store multiple object instances derived from same Base class. This created a need to create boilerplate "shell" classes inheriting from the Base class, e.g.: ImageSizeCacheSyncInMemory etc.
- Having feature-based adapter instance caching in the adapter manager allows to simplify configuration and reuse the "base class" instead of creating artificial "shell" classes.
- For example with this change both image sizes and settings caches will create separate cache instances deriving from default "Memory" class. Less code, less configuration!
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.
- we ignore some files within Casper via the Core .npmignore, but this
was outdated
- `.csscomb.json` and `.yarnrc` do not exist in the repo anymore
- `yarn.lock` should be added because this is the bundled theme files
and we don't expect to be editing them again
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/Ghost/issues/15190
refs https://github.com/TryGhost/framework/pull/76
- log output always uses UTC timestamps, but it may be desirable to
configure logs to use the local machine timezone
- a new config option has been added to `@tryghost/logging` so you can
switch the logs to the local timezone
- this commit bumps the package and sets the default config option to
`false`, so it doesn't suddenly change the timezone of the logs
- docs will be updated soon but if you'd like to use the
timezone-altered timestamps, you can set `logging.useLocalTime` to
`true`
- credits to https://github.com/levee223 for the implementation and PR
- in its current form, bundling will happen before we build Admin
- Admin complains because the version in its package.json for
`@tryghost/members-csv` is different to the one linked in the monorepo
- by putting bundling at the end, we write the new package versions
after we've already built Admin, so this issue should go away
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
- the code in question had the intention of returning early if no new
email batches had been created for an Email
- there were 2 minor bugs here:
- `batchIds` would end up being an array of an array of strings
because we just push an array in without the spread operator
- we would compare that the returned array equaled zero, which was
never the case
- this commit fixes these minor issues and adds JSDoc to document the
function's return type
no issue
- While auditing the access rights to endpoints have come across the "stable" / "experimental" notes that do not make any sense in the current approach towards the API. Every endpoint that's documented and exposed just "is" there no stable/unstable/canary/whatever distinction in the Admin API since Ghost v5
- Staff tokens were also acked as a separate way to access the API, so we have them in mind when modifying the access-list
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.
We promote from alpha -> beta so that we don't require the
enableDeveloperExperiments flag, the toggle in the UI is behind the
flag still, so it will only be visible to developers or people using
alpha features.
refs TryGhost/Team#1826
- adds new service package that manages all the email alert notifications for free members and paid subscriptions
- includes email templates for free member signup and paid subscription start/cancel
- initializes staff service before members to allow managing email alert notifications
- passes staff service to members api for triggering alerts
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
refs https://github.com/TryGhost/Toolbox/issues/387
- The limit values should be as configurable as possible to adjust verification thresholds dinamically per-usecase. This solves a problem of doing a separate version release when we need to adjust the verification thresholds.
- Before this "importThreshold" was the same concept as "apiThreshold", which makes it hard&confusing to reason about and hard to parameterize each specific case.
refs https://github.com/TryGhost/Toolbox/issues/387
- Similar reasoning as to previous renames - the variables were named with a single trigger source in mind and now would be confusing with multiple verification trigger sources.
refs https://github.com/TryGhost/Toolbox/issues/387
- There will three distinct verification limits soon. To keep the naming clear "configThreshold" would be too generic/confusing to use.
- Introduced jsdoc descriptions for the "source" parameter, which will be corelating with each new config parameter ("apiTriggerThreshold", "importTriggerThreshold", "adminTriggerThreshold", etc.). This should give a better visibility into parameters we are dealing in this area.
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.
- after a while of browsing around filtering Actions, the endpoint will
suddenly lock up and start throwing stack exceeded errors
- this is because every time we initialize an Actions model, we push to
the `candidates` array with a list of the current models
- this was producing a `candidates` array with a length of several
thousand models after a few clicks, which would cause errors when
joining the data down the line
- the code was like this because we need to lazy-initialize the models,
so the order of requiring the Actions model doesn't matter
- this commit switches the code to using a `candidates` function to get
the models
- this seems to work and the performance cost is negligible given it now
doesn't error
refs: https://github.com/TryGhost/Ghost/issues/14882
- Usage of bluebird is deprecated in favour of using native promises
Co-authored-by: Navarjun <navarjun@Navarjuns-MBP.hitronhub.home>
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.
closes https://github.com/TryGhost/Team/issues/1727
- allows site owners to give cardless free trials to members by setting expiry on complimentary subscriptions
- also allows complimentary members to upgrade as paid member
closes https://github.com/TryGhost/Team/issues/1836
- Uses the timestamps from the members table to determine the timestamps for the events
- Clears the table when downgrading to prevent having multiple rows for the same member
Co-authored-by: Fabien "egg" O'Carroll <fabien@allou.is>
- without this, the model doesn't have the context on who was
adding/editing it
- this resulted in being unable to store actions for Offers because the
`actor` is unknown
- this is the pattern we use elsewhere in the code so I've copied it
into here
refs https://github.com/TryGhost/Toolbox/issues/356
- this allows collection of CRUD events for Offers but we currently don't
show them in the UI until it's overhauled to avoid being monotonously
long
refs https://github.com/TryGhost/Toolbox/issues/356
- this allows collection of CRUD events for Tiers but we currently don't
show them in the UI until it's overhauled to avoid being monotonously
long
refs: https://github.com/TryGhost/Ghost/issues/14882
- The use of predicates is deprecated, and we're working to remove them from everywhere, so that we can remove bluebird
- This should be the final piece of the puzzle in terms of predicates, from here we can start removing bluebird without concern that a predicate somewhere will explode
- Note: some of this code is poorly tested, but the refactors are very straightforward and minimal
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
- this shouldn't ever be the case, but if we forget to label the
resource type, we shouldn't proceed with storing the event because
it'll throw an error
refs https://github.com/TryGhost/Toolbox/issues/356
- we should store the `primary_name` on `added` events too because if
the resource is eventually deleted, we won't have the pretty name to
refer to it
refs https://github.com/TryGhost/Toolbox/issues/356
refs 3a9016639c
- I misunderstood the purpose of a column, and changed the values that
are inserted into it, which broke relation includes in Bookshelf
- I've since reverted that in the commit above but this migration is to
fixup the data that got stored in the DB
- we want to replace `resource_type` = `page` back to `post`, but then
use the `context` column as described in the referenced commit to
store that the type is actually a `page`, so we can link to it
from the audit log accordingly
- I'm overwriting the `context` column without taking into account the
current contents but that's ok because this bug existed before we
started using `context`
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)
refs bde9b84221
- the commit above claimed to fix an issue where actions taken on pages
were stored using the `post` resource type
- whilst it does that, this actually breaks part of the API because we
use the `resource_type` to join on tables when doing an
`include=resource`
- this commit reverts that functionality and instead stores the type in
the `context` field so we can still differentiate between pages and
posts
- 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
no issue
We're spending a bit of time playing with an alternative to mobiledoc-kit to test it's feasibility as a base for future editor improvements.
- add `editor.lexicalUrl` config that points at the unpkg release by default
- set up a route on `/ghost/#/lexical-editor/post/` for the test playground which renders `<KoenigLexicialEditor>` as the editor
- adds `<KoenigLexicalEditor>` component that lazy loads the external react component
closes https://github.com/TryGhost/Toolbox/issues/386
- When the API request was made using staff token the source attribution was "user" instead of "api". Misattribution caused ripple effects in limit service.
- The fix also adds a new combination of data available on the `req` object - both `user` and `api_key` can be present when the request is done using a staff (user) token. Having both pieces of data on the request object gives more context for business logic, did not find a good reason to keep it "pure" with either `api_key` or `user` property.
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
closes: https://github.com/TryGhost/Ghost/issues/15251
- getAdminUrl is a config helper that returns the direct value from config
- change to using urlJoin and urlFor helpers to generate the correct URL
- not entirely happy with this fix as there's no test, but I've verified it locally
refs https://github.com/TryGhost/Team/issues/1727
- runs a daily cron job at start of the day to cleanup all expired comped subs
- removes `members<>products` mapping for expired entries, and updates status for corresponding members
- also adds status events for members going back from comp -> free as a result of expiry
- scope for future optimisation on how the scheduled job is ran or does the cleanup
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
- if a model is being deleted, `attributes` is an empty object and the
data we actually need is in `_previousAttributes`
- because of this, only fetching the type using `.get` returned the
wrong value, and the Action model validator would throw an error
because we tried to insert an empty type
- we can access the previous value using `.previous(..)`
- this commit fixes saving actions when deleting a post by fetching the
type from the previous attributes if the current attributes is empty