Commit Graph

65 Commits

Author SHA1 Message Date
Simon Backx
901a28f3c6
Added link_redirects and members_link_click_events tables (#15421)
closes https://github.com/TryGhost/Team/issues/1912
closes https://github.com/TryGhost/Team/issues/1913
2022-09-19 11:20:36 +02:00
Kevin Ansfield
3b21d26be7
Wired up creation of post_revisions entries when saving posts with lexical (#15422)
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
2022-09-16 11:59:35 +01:00
Kevin Ansfield
1581f439e9
Added post_revisions table (#15420)
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
2022-09-16 10:19:05 +01:00
Simon Backx
a7b583050c
Added link tracking to paywall (#15414)
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>
```
2022-09-16 10:08:12 +02:00
Kevin Ansfield
c240f7afa4
Added rendering of posts.lexical to posts.html when saving (#15416)
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
2022-09-15 16:49:14 +01:00
Simon Backx
e9974d8cc0
🐛 Fixed feature image caption escaped twice in newsletters (#15417)
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.
2022-09-15 17:07:10 +02:00
Simon Backx
699e67f4e4
Added email_track_clicks setting (#15409)
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).
2022-09-15 15:48:22 +02:00
Fabien "egg" O'Carroll
4726742673 Renamed redirects to custom-redirects
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
2022-09-14 13:24:17 -04:00
Kevin Ansfield
8cdd2e10b7
Added posts.lexical database field (#15397)
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
2022-09-13 11:21:47 +01:00
Rishabh
4187f0da54 Updated staff service to trigger alerts via events
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
2022-09-10 11:06:34 +05:30
Hannah Wolfe
04f3ac37d3 Removed defunct applyPublicRules code
closes: https://github.com/TryGhost/Toolbox/issues/369
refs: https://github.com/TryGhost/Toolbox/issues/229

- this code is defunct as we no longer accept a status parameter via the API for posts, pages, users or authors
2022-09-09 17:14:15 +01:00
Hannah Wolfe
b0234dd58e
Removed apiVersions from test urlUtils
refs: https://github.com/TryGhost/Toolbox/issues/229

- These properties were removed from urlUtils in 5.0 and no longer do anything
2022-09-09 13:32:30 +01:00
Ronald Langeveld
eb6534bd7f
Replaced all 'bio' references with 'expertise' for member comments. (#15359)
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.
2022-09-09 10:14:49 +02:00
Simon Backx
4534b693e4
Added test that validates output HTML of email template (#15365)
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 &lt;br /&gt; 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
2022-09-08 10:11:01 +02:00
Daniel Lockyer
4a6f57b105
Merged v5.13.2 into main
v5.13.2
2022-09-06 16:45:52 +01:00
Fabien 'egg' O'Carroll
f7a58ecafc
🐛 Fixed OpenSea NFT OEmbeds (#15372)
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.
2022-09-06 11:29:35 -04:00
Naz
920a3aeb4c
Fixed adapter-related unit test
refs 37dd187fe6
refs c36575627d/ghost/core/core/server/data/importer/handlers/image.js (L16)

- The tests were failing because they were stubbing a "generic" adapter, instead of the one which the module under test was using (see referenced code to see what I mean)
2022-09-06 18:46:32 +08:00
Naz
c36575627d
Fixed unit test
refs 37dd187fe6

- The referenced commit lacked cleanup after module removal
2022-09-06 18:11:22 +08:00
Naz
a96a7340c0
Added JSDoc to adapter options resolver
refs https://github.com/TryGhost/Toolbox/issues/384

- Added jsdoc for intellisence/typechecking
- Cleaned up the naming of returned values to resemble the usecases a bit better
2022-09-06 17:51:57 +08:00
Naz
67df9a6105
Removed unused adapterType variable
refs https://github.com/TryGhost/Toolbox/issues/384

- The adapter manager can parse the adapter type internally from the "type:feature" syntax, so there's no need to pass it around.
2022-09-06 17:51:57 +08:00
Naz
1fc8c8d671
Added more explicit adapter config syntax
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)
2022-09-06 17:51:57 +08:00
Simon Backx
2e85ae98be
🐛 Fixed sending emails from email domain that includes www subdomain (#15348)
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.
2022-09-02 16:57:59 +02:00
Daniel Lockyer
dd2bfb8c0e
Merged v5.12.4 into main
v5.12.4
2022-09-02 15:13:37 +01:00
Simon Backx
999b111fce
🐛 Fixed paid email preview stopped working in emails (#15356)
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.
2022-09-02 15:49:39 +02:00
Fabien 'egg' O'Carroll
e4cbb3d24d
Reset magic link rate limiting upon successful login (#15345)
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.
2022-09-01 08:54:14 -04:00
Naz
945ebd4806
Fixed ERR_NOCK_NO_MATCH warning during test runs
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.
2022-09-01 12:25:47 +08:00
Fabien 'egg' O'Carroll
21e473ff78
🐛 Fixed newsletters not rendering with non-HTML safe chars (#15331)
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
2022-08-30 11:26:01 +01:00
Simon Backx
a8239bfa97
Added ENUM validation for member/subscription created events (#15312)
closes https://github.com/TryGhost/Team/issues/1842

- members_created_events: source + attribution_type
- members_subscription_created_events: attribution_type
- members_subscribe_events: source
2022-08-25 15:39:37 +02:00
Rishabh
effd5af615 Handled fetching staff users for email 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
2022-08-25 18:01:52 +05:30
Rishabh
326bb97d2c Enabled free trials via tiers and offers
refs https://github.com/TryGhost/Team/issues/1724
refs https://github.com/TryGhost/Team/issues/1726

- allows site owners to add a default free trial period to their tiers
- allows site owners to create custom offers that allow free trials on tiers
2022-08-24 19:24:31 +05:30
Rishabh Garg
9abfae2ddb
Switched off email alerts for subscription cancellation by default (#15304)
refs TryGhost/Team#1825

- all sites are expected to have cancellation alerts off by default
2022-08-24 18:54:00 +05:30
Rishabh Garg
c48c65cc88
Added member email alert notification columns for staff (#15276)
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
2022-08-23 22:11:38 +05:30
Hannah Wolfe
809c1a6e08 🐛 Fixed error deleting post with comment replies
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
2022-08-19 15:49:58 +01:00
Hannah Wolfe
d2acf3aada Fixed attribution table missing on cascade delete
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
2022-08-19 15:28:45 +01:00
Rishabh
1258156c38 Handled storing complimentary subscription expiry
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
2022-08-19 18:20:52 +05:30
Rishabh Garg
43b8ad5069
Added expiry column for complimentary subscriptions (#15241)
refs https://github.com/TryGhost/Team/issues/1727

- allows adding expiry date to complimentary subscriptions, effectively allowing cardless trials.
- expiry is stored in members<>products mapping table
2022-08-19 08:41:40 +05:30
Fabien "egg" O'Carroll
37ef0582e6 Added members_subscription_created_events table & model
refs https://github.com/TryGhost/Team/issues/1803
2022-08-18 10:45:53 -04:00
Fabien "egg" O'Carroll
03155a61ff Added members_created_events table & model
refs https://github.com/TryGhost/Team/issues/1802
2022-08-18 10:45:53 -04:00
Naz
6cf49d8f89 Fixed inconsistent format of image sizes cache
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).
2022-08-16 15:20:49 +02:00
Naz
e4d02657ee Swapped image size "Map" cache for adapter cache
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
2022-08-16 12:35:35 +02:00
Naz
05eb719d0a Swapped image size cache with InMemoryCache
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.
2022-08-16 12:35:35 +02:00
Naz
e549528985 Simplified image size cache module constructor
refs https://github.com/TryGhost/Toolbox/issues/364

- As little as possible should be passed in in the parameters for any method/constructor/whatever. Specific Function > vague Object
2022-08-16 12:35:35 +02:00
Naz
92d6c998b3 Fixed error handling bug in image size cache
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
2022-08-16 12:35:35 +02:00
Naz
38c76847e9 Refactored cache image size test suite
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.
2022-08-16 12:35:35 +02:00
Naz
7d3b678d4e Refactored cached image size to have cache as DI
refs https://github.com/TryGhost/Toolbox/issues/364

- Groundwork before swapping out existing cache for in-memory cache from the adapter
2022-08-16 12:35:35 +02:00
Simon Backx
a666b846e6
🐛 Fixed unsubscribe flow for comment reply emails (#15232)
refs https://github.com/TryGhost/Team/issues/1790

- Currently we go to the account settings when you click 'Manage your email preferences' in the footer of an email that informs a comment author that they received a reply.
- Related Portal changes are here: https://github.com/TryGhost/Portal/pull/255
2022-08-15 11:36:08 +02:00
Aileen Nowak
5ac779f86b Added core type integrations to API serializer 2022-08-12 14:18:44 +01:00
Aileen Nowak
0e284edbad Allowed core integrations to work with Admin API 2022-08-12 14:18:44 +01:00
Daniel Lockyer
7d52ae52cf Deleted concept of external user
refs https://github.com/TryGhost/Toolbox/issues/363

- AFAICT, this is an outdated and unused concept from when subscribers
  were a thing, but members are now how we do things, and this is causing code
  to linger around that we don't need
2022-08-11 16:05:00 +02:00
Daniel Lockyer
42e722d627
Moved Cache-Control middleware to separate package
refs https://github.com/TryGhost/Toolbox/issues/363

- this middleware is standalone and I suspect we're going to be touching
  it further when we work on Ghost's caching in the near future
2022-08-11 14:14:20 +02:00