refs https://github.com/TryGhost/Team/issues/2371
- Adds a test that schedules a post 5 seconds in the future and waits
for it to be published
- Reduced the time restrictions for scheduling:
- The minimum time in the frontend is now 5 seconds in the future (came
from 5 minutes in the future)
- The time picker now suggests 10 minutes in the future instead of the
minimum scheduling time (came from 5 minutes)
- In the backend, a post will be allowed to be scheduled if it is at
least 2 minutes in the past (came from 2 minutes in the future)
- The scheduler will publish a post if it is at least 5 minutes in the
past, and maximum 5 minutes in the future (came from 2 minutes)
refs https://github.com/TryGhost/Team/issues/2371
- tests that a free member can upgrade to a paid tier via stripe checkout and the payment details are reflected in portal and member detail page on admin
refs https://github.com/TryGhost/Team/issues/2371
- tests modifying the content of a published post
- extracted publish flow into a `publishPost` function that returns a new browser page object with the newly created post loaded
refs https://github.com/TryGhost/Team/issues/2369
- this checks whether the Offer redemption count is set to 1, which
would be indicative that the Offer was successfully counted as
redeemed
refs https://github.com/TryGhost/Toolbox/issues/479
- this includes a handful of improvements to get Playwright working on a
local environment including:
- adding `testing-browser` environment so we don't nuke `development`
environments, and makes all the necessary changes to get Ghost to
behave when this is running
- stopped running one global instance of Ghost as this doesn't provide
a clean environment
- copies a few default fixtures that are needed for the new
environment
- we should start to keep tests grouped by their area, so first we split
by Admin tests and then Portal tests, and within that we split into
setup/Tiers/Offers etc
refs https://github.com/TryGhost/Toolbox/issues/476
- The email verification trigger and host settings related bugs have been a cause of bugs in past releases. The admin client verification source did not have any test coverage in the past.
- The members test suite size is getting out of hand. This test is quite verbose, because of the state it's trying to check.
- In the future we should consider splitting up Member API (and probably other) test suites into smaller pieces.
no issue
- The sleep method has been used in 8 modules reimplementing the same thing over and over again. It's usually a sign of async event processing outside of the request/response loop. It's good to have a single point of implementation for a "hack" like this, so we could track it easier and address the even processing delay in a more optimal way centrally if it ever becomes a bottleneck
no issue
This will need some work, since we are introducing a 500ms delay to wait for a network request to return. Ideally the tier expander should eventually populate itself.
no issue
Local tests can now setup Stripe during the global setup process, and the webhook server is run out-of-process.
Running tests in CI against localhost will use environment variables to setup Stripe.
Providing a test URL will avoid setting up Stripe and will assume that it is already done.
no issue
This commit allows tests to run remotely by replacing selectors with production-suitable ones (no [data-test...]).
It also allows running locally with Stripe webhooks by adding a new global setup function.
fixes https://github.com/TryGhost/Team/issues/2346
- Adds email batch browse endpoint
- Adds email recipient failures browse endpoint
- Adds new fixtures and E2E tests for the new API
- Added support for snapshot tests to have 'nullable' types.
refs https://github.com/TryGhost/Team/issues/2339
- Includes a new pattern in the job manager that allows us to properly
await jobs.
- Added new convenience mocking methods to stub settings
- Tests the main flows for bulk sending:
- Sending in multiple batches
- Sending to multiple segments
- Handling a failed batch and retrying that batch
- Fixes bug in batch generation (ordering not working)
In a different PR I'll add more detailed tests.
We can fetch the same event multiple times from Mailgun so we need to
be able to protect against inserting duplicate events in the
database. This will allow us to catch duplicate errors on insert when
handling complaint events.
fixes https://github.com/TryGhost/Team/issues/2332
Saves events in the database and collects error information.
Do note that we can emit the same events multiple times, and as a result
out of order. That means we should correctly handle that a delivered
event might be fired after a permanent failure. So a delivered event is
ignored if the email is already marked as failed. Also delivered_at is
reset to null when we receive a permanent failure.
closes https://github.com/TryGhost/Team/issues/2324
- It seemed like the "limit" query parameter did not work properly returning multiple entries from the endpoint. In reality the whole query string was ignored because of an error in the "filter" part of the query ^_^
refs https://github.com/TryGhost/Team/issues/2326
- The job takes considerably longer to run with MySQL, so needed a longer sleep time. It's a temporary fix to unblock a broken build. We should investigate why the job takes so long to run on MySQL
refs https://github.com/TryGhost/Team/issues/2225
- updated the `formatOnWrite` transform map for posts to include the new `nodes` and `transformMap` options used by `urlUtils` for transforming node payload data
- added `nodes` to the `lexicalLib` module that pulls in our default nodes to be passed in to the URL transform utilities
- added `urlTransformMap` to the `lexicalLib` module that maps transform type and data type to URL transform utility functions that accept a single URL argument
refs https://github.com/TryGhost/Team/issues/2317
This table is used for persisting the email suppression list.
We don't have a member_id column because emails, not members are suppressed.
fixes https://github.com/TryGhost/Team/issues/2308
- Still has some missing pieces, but mostly works.
- Uses new handlebars template for emails
- When sending emails with the new email stability flag enabled, one
test email is now sent via the default smtp ghost mailer.
fixes https://github.com/TryGhost/Team/issues/2310
This moves the processing of the events from the event-processor to a
new email-event-processor in the email-service package.
- The `EmailEventProcessor` only translates events from
providerId/emailId to their known emailId, memberId and recipientId, and
dispatches the corresponding events.
- Since `EmailEventProcessor` runs in a separate worker thread, we can't
listen for the dispatched events on the main thread. To accomplish this
communication, the events dispatched from the `EmailEventProcessor`
class are 'posted' via the postMessage method and redispatched on the
main thread.
- A new `EmailEventStorage` class reacts to the email events and stores
it in the database. This code mostly corresponds to the (now deleted)
subclass of the old `EmailEventProcessor`
- Updating a members last_seen_at timestamp has moved to the
lastSeenAtUpdater.
- Email events no longer store `ObjectID` because these are not
encodable across threads via postMessage
- Includes new E2E tests that test the storage of all supported Mailgun
events. Note that in these tests we run the processing on the main
thread instead of on a separate thread (couldn't do this because
stubbing is not possible across threads)
There are some missing pieces that will get added in later PRs (this PR
focuses on porting the existing functionality):
- Handling temporary failures/bounces
- Capturing the error messages of bounce events
refs https://github.com/TryGhost/Team/issues/2291
When sending out mails to individual recipients, its possible that recipient gets a temporary or permanent failure for receiving the mail. Temporary failures can generally get resolved after a bit when the recipient’s mail server accepts the email, unlike permanent failures. For both customer visibility and easier debugging on what went wrong while delivering to a particular recipient, we’ll store the permanent/temporary failure for a recipient.
- migration adds a new table that stores the failure information for the recipients
fixes https://github.com/TryGhost/Team/issues/2326
When importing more than 500 members, we didn't testImportThreshold at
the right time. It was called too early because the importing job was
not awaited. This also adds an E2E test for this case.
closesTryGhost/Team#2313
- Added Sent event to Post analytics and Members feed. Now post can be
Sent or Received or Bounced.
- Excluded Delivered event from Sent filter on backend.
refs https://github.com/TryGhost/Ghost/security/advisories/GHSA-9gh8-wp53-ccc6
refs https://github.com/TryGhost/Toolbox/issues/465
- Bookshelf relations allows us to edit relational records by default, which was used liberally in the codebase.
- Not having a clear track record of editable relations left the model layer prone to triggering unwanted nested saves and created a vulnerability where members were able to edit newsletter settings.
- With explicit editable relations it's easier to keep track of relations having editable access to related records. Makes the relational data modification pattern safer to use too.
- Anyone running 5.x should update to 5.24.1
Credits: Dave McDaniel and other members of [Cisco Talos](https://talosintelligence.com/vulnerability_reports)
refs https://github.com/TryGhost/Ghost/security/advisories/GHSA-9gh8-wp53-ccc6
refs https://github.com/TryGhost/Toolbox/issues/465
- Bookshelf relations allows us to edit relational records by default, which was used liberally in the codebase.
- Not having a clear track record of editable relations left the model layer prone to triggering unwanted nested saves and created a vulnerability where members were able to edit newsletter settings.
- With explicit editable relations it's easier to keep track of relations having editable access to related records. Makes the relational data modification pattern safer to use too.
- Anyone running 5.x should update to 5.24.1
Credits: Dave McDaniel and other members of [Cisco Talos](https://talosintelligence.com/vulnerability_reports)
refs: https://github.com/TryGhost/Team/issues/1121
refs: 54574025e0
- The previous change to fall back to a generic error on the server side is resulting in lots of much less useful Sentry reports
- For unexpected errors, change what's sent to Sentry back to context
- This is done by adding a specific code, so we don't have to match on a string that might change
- Also add the error type, id, code & statusCode as tags to the events - these are searchable structured data
- Adding code as a tag also makes it possible to find all errors that showed the generic message
- As demonstrated by my comments in the boot file, I thought sentry was already depending on the version package
- IMO it's undesirable to require package.json directly esp when we have a tool setup and ready for tis
- Added a bunch of tests to show that Sentry does roughly what we think
fixes https://github.com/TryGhost/Team/issues/2284
New batch sending flow (still WIP). Logs the sent emails instead of actually sending them. Unit tests are coming in later commits.
refs https://github.com/TryGhost/Team/issues/2280
We are moving away from storing html and plaintext on email and instead will store the email data in source and source_type columns which allows us to store the email in other formats like mobiledoc and lexical. Storing in those formats allows greater flexibility for later html generation
- adds new `source` column that stores `mobiledoc`/`lexical`/`html` data for a newsletter
- adds new `source_type` column that stores one of `mobiledoc`/`lexical`/`html` to identify type of source
closes https://github.com/TryGhost/Team/issues/2290
Currently, if the whole batch of email fails to send we don’t capture
any errors directly tied to the batch. This makes it hard to debug which
and why a batch failed when debugging email errors. Going forward we'll
store the error information for a failing email batch directly that
allows easier debugging for batch.
- `error_status_code` : Captures statusCode returned by Mailgun,
available in error.status from the example batch error
- `error_message` : Captures short error message from Mailgun and
status, available in context object of batch error
- `error_data` : Captures while whole error json for a batch. As
mentioned in pitch, this will be huge data and we’ll figure out long
term how to best use this.
refs: https://github.com/TryGhost/Toolbox/issues/479
Framework includes:
* command to run tests
* command to record tests
* mechanism for starting and stopping Ghost before and after each suite of tests
* mechanism for loading fixtures into Ghost before starting tests
* sample test for controlling Ghost Admin
fixes https://github.com/TryGhost/Team/issues/2282
Added a new email service package that is used when the email stability
flag is enabled. Currently not yet implemented so will throw an error
for all entry points (if flag enabled).
Removed usage of `labs.isSet.bind` across the code, because that breaks
the stubbing of labs by `mockManager.mockLabsEnabled` and
`mockManager.mockLabsDisabled`. `flag => labs.isSet(flag)` should be
used instead.
All email depending tests now disable the `emailStability` feature flag
to keep the tests passing + make sure we still run all the tests for the
old flow while the email stability package is being built.
refs https://github.com/TryGhost/Team/issues/2268
The approach of using the service to lead email suppression data as
opposed to bookshelf relations allows us to wire things up without
having implemented the database. The getBulkSuppressionData allows us to
do this without much of a DB performance hit.
closes https://github.com/TryGhost/Team/issues/2126
- Cleaned up the following GA flags: `newsletterPaywall`, `freeTrial`, `compExpiring`, `searchHelper`, `emailAlerts`, `fixNewsletterLinks`.
refs https://github.com/TryGhost/Team/issues/2246
- This change helps avoid race conditions due to a lack of a transaction
in the email job. It also moves the status check before creating the
email batches (can take a while) to prevent other timing issues in case
the job got scheduled multiple times.
- Sets the patch option to true when changing the status of an email
batch. If we don't do this, the bookshelf-relations plugin might try to
save relations too. This could have caused a 'no rows updated' error.
- Added a test that tests if the email job can only run once
- Added logging to batching logic
- updated the cover image to be simpler
- made the change in text fixtures as well, just to keep the fixtures in sync
Co-authored-by: Hannah Wolfe <github.erisds@gmail.com>
fixes https://github.com/TryGhost/Team/issues/2085
Don't load relations we don't need anymore for the posts table. And
reload the individual post when we open the analytics page with more
relations that we actually need.
refs https://github.com/TryGhost/Team/issues/2216
The `membersActivity` flag was an alpha feature to test the first versions of member analytics, and is no longer active or in use. This change removes the remaining pieces of code that are setup behind that flag and are no longer in use or accessible.
refs: https://github.com/TryGhost/Ghost/issues/14882
This commit totally removes Bluebird from the importer. Updated `@tryghost/promise` to use native async/await and refactored importer logic to avoid the need of `reflect()`.
fixes https://github.com/TryGhost/Team/issues/1903
MembersAgent.loginAs sends email, asynchronously via events. Which
conflicts with tests that also test emails. We cannot properly await
these events, so this is currently fixed with a timeout of 200ms. But
this was too random and unreliable.
closes https://github.com/TryGhost/Team/issues/2222
Whilst we were checking for Stripe objects being active, we were not
checking for them existing in Stripe. This adds handling to all read
request to Stripe in the payment link flow, so that we can gracefully
handle deleted objects.
We've also included an automated test which fails without this fix.
We've also improved the query to find Stripe Prices which will result
in less request to the Stripe API to check if it is valid.
closes https://github.com/TryGhost/Team/issues/2207
- adds conditional to the post email serializer to switch between
`mobiledocLib` and `lexicalLib` depending on which format the post
contains
closes https://github.com/TryGhost/Team/issues/2211
We were allowing paid Tiers to be imported with non-integer prices which was
causing the Admin to be bricked when attempting to load them. This adds some
validation to the price data of Tiers.
refs https://github.com/TryGhost/Toolbox/issues/461
- The 'vary' header with 'Origin' value should only be set when an OPTIONS header is processed. Otherwise we are prone to leaking the vary header modification to further down in the request pipeline
refs https://github.com/TryGhost/Toolbox/issues/461
- The unit test was never using the "OPTIONS" request method, which did not actually trigger the full logic of the "cors" module used under the hood.
- Using the correct request method triggers all the right pathways and tests the state that's closer to the real world - for example the response does get "ended" instead of calling the "next" middleware.
refs https://github.com/TryGhost/Toolbox/issues/461
- Having a 'Origin' in vary header value present on each `OPTIONS` allows to correctly bucket "allowed CORS" and "disallowed CORS" responses in shared caches
refs https://github.com/TryGhost/Toolbox/issues/461
- Having a 'Origin' in vary header value present on each `OPTIONS` allows to correctly bucket "allowed CORS" and "disallowed CORS" responses in shared caches
refs https://github.com/TryGhost/Toolbox/issues/461
- The codebase has ambiguous behavior with OPTIONS request. Adding tests covering edge cases for all possible variations of OPTIONS responses is the first step to solving cahceability of these requests.
- The obvious question if you look into the changeset itself would also be: "WTF did you do with test suite naming? What are these changes in admin and click tracking suites? You having a bad day Naz?". The answer is "yes" (╯°□°)╯︵ ┻━┻
- On a serious note. I've introduced multiple hacks here that should be fixed:
1. Forced test suite execution order for options request - extreme blasphemy. This was last resort decision. I went deep into trying to fixup the server shutdown in the "admin" test suite, which cascaded into failing "click tracking" suite, which has shortcomings on it's own (see notes left in that suite)
2. Exposed "ghostServer" from the e2e-framework's "getAgentsWithFrontend" method. Exposing ghostServer to be able to shut it down (or do other manipulations) was one of the pitfalls we had in the previous test utils, which ended up plaguing the test codebase. Ideally the framework should only be exposing the agents and the rest would happen behind the scenes.
- To fix the hacks above I've raised a cleanup issue (https://github.com/TryGhost/Toolbox/issues/471). I'm very sorry for this mess. The issue at hand has very little to do with fixing the e2e framework, so leaving things "as is".
refs https://github.com/TryGhost/Toolbox/issues/461
- When testing OPTIONS requests there is a need to get all possible agents available in the system. The "getAgentsWithFrontend" serves exactly this purpose - create all possible agents while starting Ghost instance only once
- This is groundwork for OPTIONS request caching tests and improvements
refs https://github.com/TryGhost/Ghost/commit/1f300fb781f0
The full customer object was not being passed to the StripeAPI service
when it already exists, this was resulting in inconsistent behaviour when
sending the customerEmail param to the API, causing `invalid_email`
errors to be thrown from Stripe and breaking the checkout.
closes https://github.com/TryGhost/Team/issues/2196
We were incorrectly assuming that all requests would have the
`customerEmail` passed in the body. Instead we were incorrectly
passing `undefined` or `''` as the `customerEmail` property to stripe,
which resulted in a validation error.
We've updated the code to pass `null` in the case of a falsy value,
which the Stripe API handles without error.
closes https://github.com/TryGhost/Team/issues/2195
The issue here is two-fold, and specific to using Offers so was not
caught by any automated tests. First, we were incorrectly comparing
the tier.id to the offer.tier.id - this is because the Tier objects id
property is an instance of ObjectID rather than a string.
Secondly we were passing through the cadence parameter from the
request body, but when using Offers this is not including in the
request, so we must pull the data off of the Offer object instead and
pass that to the payments service.
closes https://github.com/TryGhost/Ghost/issues/15740
The validation function for a Tier description was not returning the
validated value, which meant we were unable to set the Tier
description.
refs https://github.com/TryGhost/Toolbox/issues/464
Bceause the import does not use the API, any backwards compat code we put in the
API does not get run for imports, this means we need to update the importer to
map the stripe_prices data onto the products table so that we have valid data in
the database.
refs: a8b1676734
- Extended the newly created handlebars test utils with a shouldCompileToError method
- Updated the price helper tests tp use shouldCompileToExpected and shouldCompileToError
- This allows us to test our handlebars helpers in a much more conisstent way
no issue
- There are currently two patterns in our handlebars helper unit tests:
1. Treating the helper as a function, and doing a function call
- This is the original way the tests were done, and they're not great as they're approximating how the helpers are really used
2. Using a template string, and rendering the string using a method called shouldCompileToExpected
- These tests are more realistic and powerful and also easier to read
- The new method is only being used in a few places so far, and each place had re-created the `shouldCompileToExpected` method
- Therefore I've moved this method into a util that should make it easier to write unit tests for handlebars helpers
- I also renamed the method in the excerpt tests, because it doesn't do the same thing, it's just a wrapper around a function call rather than compiling a string
The aim is to refactor all of our handlebars helper tests to use `shouldCompileToExpected`
- These tests are very slow, and make the build fail about 2/3 times
- Temporarily skipping until we can fix, as I want to get all our outstanding hacktoberfest PRs merged
fixes https://github.com/TryGhost/Team/issues/2175
- New event type `aggregated_click_event` that is disabled by default in all the existing activity feeds
- This returns click events, but only the first click events for each member/post combination.
- It includes the total count of unique link clicks for that member on that post combination
- Had to resort to some custom knex queries to make this work easily
- Requires `@tryghost/bookshelf-pagination@0.1.31`, included in `@tryghost/bookshelf-plugins@0.6.1` (this fixes an issue with custom selects breaking the total count query of pages)
- Went a bit overboard with the pagination tests to cover as much unknown edge cases as possible
refs https://github.com/TryGhost/Team/issues/2168
- site owners can now disable tracking sources from analytics settings.
- this change removes the loading of attribution script if tracking is
turned off so we don't capture any post/page or external source
attributions
refs https://github.com/TryGhost/Team/issues/2168
- the new setting allows site owners to control if they want to track
the sources for new member signups and subscriptions
- its switched on by default, but can be toggled off from new analytics
settings page
fixes https://github.com/TryGhost/Team/issues/2129
- This changes how the activity feed API parses the filter.
- We now parse the filter early to a MongoDB filter, and split it in two. One of the filters is applied to the pageActions, and the other one is used individually for every event type. We now allow to use grouping and OR's inside the filters because of this change. As long as we don't combine filters on 'type' with other filters inside grouped filters or OR, then it is allowed.
- We make use of mongoTransformer to manually inject a mongo filter without needing to parse it from a string value again (that would make it a lot harder because we would have to convert the splitted filter back to a string and we currently don't have methods for that).
- Added sorting by id for events with the same timestamp (required for reliable pagination)
- Added id to each event (required for pagination)
- Added more tests for filters
- Added test for pagination
- Removed unsued getSubscriptions and getVolume methods
Used new mongo utility methods introduced here: https://github.com/TryGhost/NQL/pull/49
refs https://github.com/TryGhost/Team/issues/2077
- Members and Posts test suites were using a broad tiers property matcher, which is an anti-pattern for snapshot tests. Without more specific snapshots it would be very hard to track down tier-related breaking changes!
- This change is groundwork for a refactor coming in tier usage at API's output serializers
closesTryGhost/Team#2159
- Added column to email table
- Hide the feedback tab on frontend depending on the column value
Co-authored-by: Daniel Lockyer <daniellockyer@fastmail.com>
refs: https://github.com/TryGhost/Ghost/issues/15537
- snapshot test created to add confidence to webhook stability and increase overall test coverage.
Co-authored-by: Kritika Sharma <kritikasharma@Kritikas-MacBook-Pro-2.local>
fixes https://github.com/TryGhost/Team/issues/2137
For the analytics page, we need the sent events to show up immediately
after sending an email. Otherwise we need to wait for emails to be
marked as received (which takes too long) before being able to show them
on the analytics page.
This adds the email_sent_event, which is hidden by default everywhere
and used on the analytics page.
refs: https://github.com/TryGhost/Ghost/issues/14882
- Opted to use the in-house `sequence` function when refactoring Bluebird's `Promise.each` to avoid deadlock issues (see 734ef66e6c).
-It's hard to know without tonnes of context if any `Promise.each` are safe to refactor to `Promise.all`.
refs https://github.com/TryGhost/Team/issues/2116
- allows site owners to edit a link in a post that has already been sent out, fixing any typos or other mistakes
- resets click counter for the edited link back to 0 so site owners can see the clicks on new link, doesn't change the overall click count
refs https://github.com/TryGhost/Team/issues/2135
The email link redirects on Pro are cached as 302 redirects in Varnish, so we're missing further clicks after the first one for each member, until the cache is invalidated. This change invalidates cache on link edits to ensure that we correctly redirect members to updated link everytime
refs https://github.com/TryGhost/Team/issues/2034
- this table will be used to link Stripe subscriptions to Ghost
subscriptions via a foreign key that we add at a later point
- this also includes `constraintName` as the auto-generated one would be
too long for MySQL 8
refs https://github.com/TryGhost/Team/issues/2104
- adds edit permissions for links endpoints to fixtures
- new `bulkEdit` endpoint will use the permissions and allow fixing newsletter links via Admin
refs 5fcf5098a8
- links browse endpoint had permissions switched off unintentionally and was also missing the necessary permissions in fixtures.
- enables permissions for browse endpoint and adds migration insert permissions in DB
fixes https://github.com/TryGhost/Team/issues/2090
- This changes how sentiment is exposed in the API. Now it is exposed as a `sentiment` relation, directly on the model (no longer in counts). Internally we still use `count.sentiment`.
- Content API users (and themes) can include the 'sentiment' relation and order by sentiment.
- Updated Admin to use sentiment instead of count.sentiment
fixes https://github.com/TryGhost/Team/issues/2091
fixes https://github.com/TryGhost/Team/issues/2089
- Added new fixtures to make testing easier for the activity feed
- Improved E2E test coverage of activity feed with separate test file
- Added data.post_id filter to enable filtering by events related to a
given post
- Fixed return types in JSDoc of test agents (TypeScript interprets
these as `typeof Agent` if we don't add `InstanceType<Agent>`)
- Added total pagination metadata to activity feed API (to allow a basic
type of pagination using filters)
fixes https://github.com/TryGhost/Team/issues/2096
When generating the recipient data for emails, the email clicks
implementation is resulting in a recipient variable being added called
replacement_xxx once for each link containing the same UUID.
This generates a lot of unnecessary data overhead for emails, and it
turns out that mailgun has a 25MB message limit. We wouldn't have come
close if we only included the uuid once.
fixes https://github.com/TryGhost/Team/issues/2102
- this column was added with `nullable: true` but it should never be
nullable, so we should drop the nullable status whilst it's easy to
fixes https://github.com/TryGhost/Team/issues/2084
- When audience feedback is enabled, we use a single 'conversions' count instead of having separate ones for signups and paid conversions.
- The analytics component is separated so we can change it without breaking the existing page.
refs https://github.com/TryGhost/Team/issues/2072
Google is indexing our redirects and storign the redirected content
against the redirect URL in search results. This seems to be caused by
us using a 302 redirect rather than 301. We don't want to switch to a
301 however, so that we can support the ability to update redirects in
the future.
refs https://github.com/TryGhost/Team/issues/1765
In order to better handle deleted objects in Stripe we want to decouple
Members from Stripe.
These changes allow us to have the Tier concept completely independent
of the Stripe tables, such that the Stripe data can be generated as/when
it's needed - which will help to protect against missing data.
closes: https://github.com/TryGhost/Ghost/issues/14973
- When fetching content using a non-standard charset, characters were notproperly decoded to utf-8 resulting in mangled text in the editor -> Detect charset and use iconv to decode the page text
- When requesting a non bookmark card, if no oembed data could be foundand we fallback to bookmark, a second network request to fetch the content was issued. This seemed unnecessary -> refactored to avoid that
refs: https://github.com/TryGhost/Ghost/issues/15537
- snapshot test created to add confidence to webhook stability and increase overall test coverage.
Co-authored-by: Kritika Sharma <kritikasharma@Kritikas-MacBook-Pro-2.local>
refs https://github.com/TryGhost/Team/issues/2030
- adds `subscriptions` table to the DB schema
- this new table is aimed to support a native "subscription" primitive in Ghost
that most resembles previously used `members_stripe_customers_subscriptions` table
refs https://github.com/TryGhost/Toolbox/issues/441
- whilst reviewing another PR, I noticed we were incorrectly using
`maxLength` instead of `maxlength` in the schema column definition
- it turns out we've already been doing this wrong for a while with
other columns
- this key is not acted upon, so the maximum column length was not applied
- fixing up the DB to the correct maximum length is something to fix in the
future but right now, the schema does not reflect the size of the
column that actually got created
- the fallback when `maxlength` is not provided is currently 191 [0], so
this commit switches the schema and migrations to using the correct
key name and column length that they are using when applied
[0]: 24670aa555/ghost/core/core/server/data/schema/commands.js (L27)
refs https://github.com/TryGhost/Toolbox/issues/441
- we tend to have a mix of `bool` and `boolean` in the schema and
migrations, which has become a real nit for me at this point
- we don't do any special handling between `bool` and `boolean`, it's
just something we pass to Knex
- `bool` is an alias for `boolean` but `boolean` is actually documented - https://knexjs.org/guide/schema-builder.html#boolean
- this commit switches Ghost to only using `boolean` in the schema and
migrations, and removes `bool` from the allowlist in tests to prevent
us from adding it again in the future
- this should make absolutely no difference to the DB because both
resulted in the same column
refs https://github.com/TryGhost/Toolbox/issues/441
- I'm currently working on cleaning up our uses of `bool` and `boolean`
in favor of `boolean`, and I've noticed we only handle converting
numbers into booleans when the type is `bool`, so validation would
otherwise fail
- given these can be used interchangeably, we should also support
converting the numbers into booleans when the type is `boolean`
- this is going to get cleaned up again when I remove `bool` but this
fixes the validation bug for now
refs: https://github.com/TryGhost/Ghost/issues/15537
- snapshot test created to add confidence to webhook stability and increase overall test coverage.
Co-authored-by: Kritika Sharma <kritikasharma@Kritikas-MacBook-Pro-2.local>
refs: https://github.com/TryGhost/Ghost/issues/15537
- this adds an e2e test and test snapshot for the `tag.edited` webhook so we can prevent regressions and bugs in the future
Co-authored-by: Hannah Wolfe <github.erisds@gmail.com>
closes: https://github.com/TryGhost/Ghost/issues/14981
- Taxonomy-specific sitemaps were invalid xml when there was no data
- These invalid empty sitemaps were referenced in the index sitemap causing SEO tools to report errors
closes: https://github.com/TryGhost/Ghost/issues/15470
- When multiple browser tabs are open, each manipulate a different copy of ember data model, changes to the model in one tab are not reflected in the model of the other tab.
- When updating some settings, all current settings were sent to the API.
- As a result, when updating two different categories of settings (navigation/code inspection) in different tabs, the second update was overriding the first one.
- From a user perspective, this is not a natural behaviour. Only settings visible on-screen when clicking save should be modified.
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
refs https://github.com/TryGhost/Toolbox/issues/441
- this is only v1 of the test I would like but it validates the keys on
a column definition are part of an allowlist
- this has already uncovered a bug with `maxLength` (vs `maxlength`)
fixes https://github.com/TryGhost/Team/issues/2054
This change adds the sentiment and positive_feedback counts to the posts models. This change isn't really ideal because there are some problems here:
- sentiment isn't really a count
- we don't need to include the sentiment and positive_feedback as a default for posts (but the same is true for attribution)
It would make sense to move this to separate endpoints that only fetch the analytics for a given post when the analytics page is opened. But for our initial skateboard version of audience feedback this should be a good start to already see the data.
refs https://github.com/TryGhost/Team/issues/2047
- We anticipate upcoming changes in the PUT /members/:id/subscriptions/:subscription_id endpoint , so covered it with a snapshot test to track the differences more precisely.
- Note, the test case contains a more explicit outgoing HTTP request mocking.
refs https://github.com/TryGhost/Team/issues/1967
This tests the full flow of publishing a newsletter, and then checking
that clicked links will increase the click count, generate events for
the member which clicked the link as well as the redirects contain the
correct query params.
refs https://github.com/TryGhost/Toolbox/issues/320
- Added more complex mobiledoc structure in the post.published test to check for correct transformation of special purpose `__GHOST_URL__`. The snapshot has a correct URL transformation, which gives confidence it works properly
refs https://github.com/TryGhost/Toolbox/issues/320
- There noe "roles" attached to the post's author when the 'post.added' event is fired. Webhooks function based of the model events and differ slightly with it's output comparing to the API response. For example, in case of Posts API, there'a an additional 'findOne' call (ref.: https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/server/models/post.js#L1224-L1227) before returning the post to the endpoint handler and then passing that to the output serializer.
- If we want to have 1:1 copy of webhooks outputs and API outputs, we should rethink how we rely on model event data which is never the same as API controller level data.
refs a499f866f3
refs d817e5830d
- The user-agent used in outgoing Ghost requests (webhooks mostly) is dependent on the Ghost version - snapshots break if the matcher is not dynamic.
- There will be a few more webhooks tests coming soon, so makes sense to have this matcher moved to a common "framework matchers"
fixes https://github.com/TryGhost/Ghost/issues/14508
This change requires the frontend to send an explicit `emailType` when sending a magic link. We default to `subscribe` (`signin` for invite only sites) for now to remain compatible with the existing behaviour.
**Problem:**
When a member tries to login and that member doesn't exist, we created a new member in the past.
- This caused the creation of duplicate accounts when members were guessing the email address they used.
- This caused the creation of new accounts when using an old impersonation token, login link or email change link that was sent before member deletion.
**Fixed:**
- Trying to login with an email address that doesn't exist will throw an error now.
- Added new and separate rate limiting to login (to prevent user enumeration). This rate limiting has a higher default limit of 8. I think it needs a higher default limit (because it is rate limited on every call instead of per email address. And it should be configurable independent from administrator rate limiting. It also needs a lower lifetime value because it is never reset.
- Updated error responses in the `sendMagicLink` endpoint to use the default error encoding middleware.
- The type (`signin`, `signup`, `updateEmail` or `subscribe`) is now stored in the magic link. This is used to prevent signups with a sign in token.
**Notes:**
- Between tests, we truncate the database, but this is not enough for the rate limits to be truly reset. I had to add a method to the spam prevention service to reset all the instances between tests. Not resetting them caused random failures because every login in every test was hitting those spam prevention middlewares and somehow left a trace of that in those instances (even when the brute table is reset). Maybe those instances were doing some in memory caching.
fixes https://github.com/TryGhost/Ghost/issues/14508
This change requires the frontend to send an explicit `emailType` when sending a magic link. We default to `subscribe` (`signin` for invite only sites) for now to remain compatible with the existing behaviour.
**Problem:**
When a member tries to login and that member doesn't exist, we created a new member in the past.
- This caused the creation of duplicate accounts when members were guessing the email address they used.
- This caused the creation of new accounts when using an old impersonation token, login link or email change link that was sent before member deletion.
**Fixed:**
- Trying to login with an email address that doesn't exist will throw an error now.
- Added new and separate rate limiting to login (to prevent user enumeration). This rate limiting has a higher default limit of 8. I think it needs a higher default limit (because it is rate limited on every call instead of per email address. And it should be configurable independent from administrator rate limiting. It also needs a lower lifetime value because it is never reset.
- Updated error responses in the `sendMagicLink` endpoint to use the default error encoding middleware.
- The type (`signin`, `signup`, `updateEmail` or `subscribe`) is now stored in the magic link. This is used to prevent signups with a sign in token.
**Notes:**
- Between tests, we truncate the database, but this is not enough for the rate limits to be truly reset. I had to add a method to the spam prevention service to reset all the instances between tests. Not resetting them caused random failures because every login in every test was hitting those spam prevention middlewares and somehow left a trace of that in those instances (even when the brute table is reset). Maybe those instances were doing some in memory caching.
no issue
- All content-length snapshots should be using the same matcher for consistency - anyContentLength. It's more explicit about what the matcher is all about and might be useful to have content-length matchers in one place if it ever changes (the header value should be a damn digit after all, not a string!) (ref. https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2)
refs https://github.com/TryGhost/Team/issues/2024
Without validation it was possible to send a string of comma separated
email addresses to the endpoint, and an email would be sent to each
address, bypassing any rate limiting.
This bug does not allow for an authentication bypass exploit. It is purely a
spam email concern.
Credit: Sandip Maity <maitysandip925@gmail.com>
refs https://github.com/TryGhost/Toolbox/issues/320
- The URL matcher is very likely to be reused in the future, so having it abstracted away gives two benefits:
1. Central place to document hacky behavior and easier future cleanup
2. The implementer of the e2e test does not have to see the "hacky note" and just concentrate on the implementation of the test
refs https://github.com/TryGhost/Toolbox/issues/320
- Header snapshot matching was missing from webhook e2e tests. With a bumped version of webhook-mock-receiver it's now possible to record and match webhook request headers.
closesTryGhost/Team#2007
- uses request context to add referrer source and medium for a new member
- uses integration name as referrer medium if exists
fixes https://github.com/TryGhost/Team/issues/2008
- New column that stores email click tracking at the time it was created
- Improved frontend side checks for when to show analytics
refs https://github.com/TryGhost/Toolbox/issues/425
refs https://github.com/TryGhost/Toolbox/issues/280
- The versioned API responses vary based on requested version (passed in request's 'accept-version' header). shared caches that sit between Ghost's origin server and the browser would be putting responses with same Vary into the same caching bucket, which is incorrect.
- This change makes response's Vary more granular and tells caching mechanisms to take 'Accept-Version' request header into account when caching.
- Informative read on the topic - https://www.fastly.com/blog/getting-most-out-vary-fastly
- renames `refSource`, `refMedium` and `refUrl` to `referrerSource`, `referrerMedium` and `referrerUrl` respectively for consistent naming across files and usages
- bumps member attribution script from alpha feature to now load for all sites. The script captures recent url history in localstorage to capture correct attribution for members.
- script is only loaded on the site if members is enabled
refs https://github.com/TryGhost/Team/issues/1967
- Test is good to test if the whole flow works as expected, and works together
- We can test independent parts in separate tests that have better coverage of more edge cases
- Adds a basic helper to get an agent for the frontend (spent too much time on a better solution so I decided to keep the existing supertest agent)
refs https://github.com/TryGhost/Ghost/pull/15471#discussion_r979902374
- the accent color value used by default content cta was copying the global site property which is redundant, and can be directly used
- originally, the accentColor property was extended to allow a fallback value for content ctas, but was later removed as we added default value to global site property directly
- the accentColor property is now deprecated and will be removed in next version, as existing themes might be relying on it for custom cta helpers
closes https://github.com/TryGhost/Team/issues/1898
- the default content cta always used the terminology as `post` when showing message that users don't have access to some content
- this caused confusion when users were looking at a page and message showed "This post is for subscribers only"
- updates the message to correctly reflect `page` vs `post` on the default cta
refs https://github.com/TryGhost/Toolbox/issues/410
- Private cache control was preventing browser or shared caches from storing Content APIs response. The type of data served through the Content API is very much of a "public" nature, so should be cacheable.
- Right now the 'max-age' value of 'cache-control' header is hardcoded to '0', without 'must-revalidate' value, to allow browsers to cache content slightly more aggressively. In the future the 'max-age' value will most-likely become configurable to allow even more aggressive HTTP caching.
refs https://github.com/TryGhost/Toolbox/issues/410
- The 'private' value in 'Cache-Control' response header for all errors made it impossible for shared caches (e.g.: Fastly, Cloudflare) to cache 404 responses efficiently.
- The change substitutes 'max-age=0' which should not effect the browser cache behavior but would allow shared caches to process such requests efficiently.
- A more loose caching logic only applies to 404 responses from GET requests that are not user-specific (non-authenticated, non-cookie containing requests)
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
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
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
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
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
- 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/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
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
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.
refs https://github.com/TryGhost/Team/issues/1799
Rather than using the `adminAuthAssets` config which is not updated to
be aware of running in a different directory to the cwd, we use the
getContentPath method which handles all of the directory checking.
Without this, we were unable to serve the admin-auth iframe, as the
directory was incorrect for self hosters.
- we've had an optimization in CI that copies a fresh SQLite DB to a
file, and copies it back when we need to do a DB reset
- I originally only let this run in CI but we've had it around for a
while so we should GA it to run on local machines
- there may be edge cases, but we should fix them instead of letting
tests run slower for development
- this also makes sure we clean up any existing files before
initializing the DB
- prior to this commit, if you add or remove a faeture flag, you also have to update the snapshots for the settings tests
- feature flags are intended to be very easy to add and remove, and so this extra step doesn't fit with our needs
- it's also unnecessary, we don't need to verify the exact contents of the labs setting
- added core and builtin integrations to test fixtures
- allowed passing a custom api key id to generate JWT
- updated admin key auth test to make successful request with a `core` integration, which doesn't work atm because relations are not returned
refs https://github.com/TryGhost/Toolbox/issues/363
- this API framework is standalone and should be pulled out into a
separate package so we can define its boundaries more clearly, and
promote better testing of smaller parts
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
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
refs https://github.com/TryGhost/Team/issues/1726
- free trial offers don't need a stripe coupon created for them
- checkout sessions for free trial offers ignore stripe coupon and directly pass the trial days value
- trial days of an offer take precedence over trial days added as default to a tier
refs https://github.com/TryGhost/Toolbox/issues/363
- this commit pulls all code involving the Mailgun client SDK into one
new package called `mailgun-client`
- this means we should be able to replace `mailgun-js` (deprecated) with
`mailgun.js` (the new, official one) without editing code all over the
place
- this also lays some groundwork for better testing of smaller
components
refs https://github.com/TryGhost/Team/issues/1723
- Added count.replies to comments
- Added replies endpoint
- Limited returned replies to 3.
- Replaced likes_count with count.likes in comments
- Instead of fetching all the likes of a comment to determine the total count, we'll now use count.likes
- Instead of fetching all the likes of a comment to determine whether a member liked a comment, we'll now use count.liked (which returns the amount of likes of the current member, being 0 or 1). This is mapped to `liked` to make it more natural to work with.
The `members.test.snap` file changed because we no longer include `liked: false` if we didn't fetch the liked relation. And in the comments events of the activity feed the liked property is therefore removed.
These changes requires an update to the `bookshelf-include-count` plugin:
- Updated to also work for nested relations
- This moves the count queries from the `bookshelf-include-count` plugin to the `countRelations` method of each model.
- Updated to keep the counts after saving a model (crud.edit didn't return the counts before)
refs https://github.com/TryGhost/Team/issues/1760
This allows theme developers to wrap the output of the comment_count
helper in an element, which will only be shown when there is content
to output.
This makes styling a lot easier, as the default output for no comments
is nothing, meaning that separators defined with CSS will not be rendered.
refs https://github.com/TryGhost/Team/issues/1757
- exposes trial start and end dates in member's subscription object
- allows portal and admin to show member's trial information in UI
refs https://github.com/TryGhost/Team/issues/1745
This is done at the mapper layer, so that the model can be used for the
Admin API - where will probably want to expose the underlying content.
We've also disabled editing of deleted/hidden comments, to avoid
accidentally overriding the comments html when sending up deleted
comments.
refs https://github.com/TryGhost/Team/issues/1724
With free trials, members can start subscriptions with a trial period. This change stores the information about trial start and end date for every subscription so it can be shown on Admin/Portal for member.
- adds new `trial_start_at` column for storing trial start date on Stripe subscription. Will in most cases match the start of subscription date.
- adds new `trial_end_at` column for storing trial end date on Stripe subscription.
- wires storing trial start and end values on stripe subscription
closes: https://github.com/TryGhost/Ghost/issues/14980
refs: cc276486f0
- Tenor is now operated by Google, and the old v1 Tenor API has been decommissioned
- At present anyone with a pre-configured tenor integration will get intermittent errors, whilst it is impossible to setup a new tenor API integration
- Sadly old keys do not work with the new API, and new keys do not work with the old API, so there is no happy path forward.
- After this lands, everyone will need to go and get a new Google API Key for Tenor, update their config, and then the integration will work properly again.
- This particular change renames the API key from `publicReadOnlyApiKey` to `googleApiKey` to reflect that the key itself changes in type and behaviour
Co-authored-by: Hannah Wolfe <github.erisds@gmail.com>
refs https://github.com/TryGhost/Toolbox/issues/364
- Settings Manager used to store all of it's settings values in a hash - an in memory cache in disguise. Having a hidden cache made it hard to reason about it's impact of memory usage and did not allow to swap it out for an alternative storage metchanism easily. Having a cache storage abstraction in Settings Manager allows to get rid of long lasting memory problems + decouples storage mechanism from the logic around transforming stored values.
refs https://github.com/TryGhost/Toolbox/issues/364
- This is groundwork to substitute in memory caches we use across the codebase. The first candidate would be settings cache. The interface of the memory cache was kept to the minimum. The "keys" method is a somewhat acceptable alternative to the "getAll" method used in the codebase right now.
- The next iteration over this would be adding async methods are alternative key/value storage methanisms like Redis.
refs https://github.com/TryGhost/Toolbox/issues/364
- Passing "cache" through constructor did not work out because cache setting is still dependent upon on the model layer (gets called before it has a chance to initialize during db migrations)
- To remove the initialization dependency blockers were:
"defaults" method in the post model - the value resolved to "undefined" anyway during the fixture insertion
validate-password module - checks the password against "undefined" during fixture initialization
- Passing the cache through "init" method works too, but is not as clear as with constructor DI pattern.
refs https://github.com/TryGhost/Team/issues/1716
- Adds the bio field to the API output
- Allow setting bio when updating the member
- Includes new E2E tests for the members API that were missing
refs https://forum.ghost.org/t/admin-template-issues-default-install/31750
- we recently switched to using different folders within `core/built`, to
indicate the assets that are applicable for development/production
environments
- unfortunately, this came with the side effect of the "development" assets
missing in the published tarball, which meant Admin wouldn't load when
running in development mode
- this was a regression from how it previously worked because we used to
just copy the production HTML file to the development HTML name, and
use the same assets
- after thinking about it, I think we can get rid of the split folders
for assets, because I don't think the use-case is there for having
them:
- if you run Ghost from source, you're 99% only using the
development-built assets
- if you want production ones, you can run with a flag, but the
development ones get wiped anyway
- those running Ghost from a published package are using the same
assets and HTML file
- therefore, I think we can make our lives simpler by removing the env
folders and using a folder under `core/built/admin/...`
- this commit implements that across Ghost and Admin
refs https://github.com/TryGhost/Team/issues/1724
- storing trial period days allows site owners to give free trial for N days to all members signing up on a tier
- by default, all tiers have 0 trial period days(same as no trial)
refs https://github.com/TryGhost/Toolbox/issues/363
- this shared library is standalone, and it used in various places of
Ghost core, so we can pull it out to keep it easier to reason about
- we also use the `html-to-text` dependency in another package but it's
outdated and could now switch to this new package
refs https://github.com/TryGhost/Team/issues/1695
We add english defaults for the singular and plural params leaving the
empty param blank so as to not draw attention to low engagement.
refs https://github.com/TryGhost/Team/issues/1695
When a post does not have any comments we were not returning any data
from the API, which would cause issues with the comment counts helper
frontend script. This updates the endpoint to always include the count
when explicitly requesting the count for specific posts.
We've also pulled the logic out into a stats service so that the endpoint
can just refer to the controller.
refs https://github.com/TryGhost/Team/issues/1695
This updates the comment_count helper from a block to inline, and the
frontend script to replace the entire element with the comment count
text. This means that theme designers will have the most flexibility
as they can choose whether or not to wrap the text in an element, as
well as which element.
no issue
- The linter does not seem to pickup the trailing whitespace problem in test files. This would be good to fix project-wise with the `--fix` options or something similar
- This change is for example purpuses :)
refs https://github.com/TryGhost/Toolbox/issues/364
- This is a groundwork which moves the "cache" property in settings cache to be injectable parameter, so we can swap it out with different implementations.
- The module will be broken downn into two concepts - an injectable cache and a cache manager (the update system)
refs https://github.com/TryGhost/Admin/pull/2252
closes https://github.com/TryGhost/Team/issues/1182
- Admin now copies it's build output to a single env-specific directory rather than splitting html and assets
- `core/built/admin/{development|production}/*`
- updated the admin app's `serveStatic` definition for assets and controller's html serving to reflect the new asset paths
fixes https://github.com/TryGhost/Ghost/issues/14323
- Fixed support for resizing images from Unsplash using the `img-url` helper (previously the size property was ignored for images from Unsplash)
- Added support for `avif` file formats (supported by sharp out of the box)
- Added support for setting the format of images, with a new `format` option:
E.g. to convert an image to webp (only works in combination with size for now, except for Unsplash where you can use it without size):
```
{{img_url @site.cover_image size="s" format="webp"}}
```
This can help improve the performance of a theme, by serving assets in `<picture>` elements with webp and fallback image formats.
Usage example:
```html
<picture>
<source
srcset="{{img_url feature_image size="s" format="avif"}} 300w,
{{img_url feature_image size="m" format="avif"}} 600w,
{{img_url feature_image size="l" format="avif"}} 1000w,
{{img_url feature_image size="xl" format="avif"}} 2000w"
sizes="(min-width: 1400px) 1400px, 92vw"
type="image/avif"
>
<source
srcset="{{img_url feature_image size="s" format="webp"}} 300w,
{{img_url feature_image size="m" format="webp"}} 600w,
{{img_url feature_image size="l" format="webp"}} 1000w,
{{img_url feature_image size="xl" format="webp"}} 2000w"
sizes="(min-width: 1400px) 1400px, 92vw"
type="image/webp"
>
<img
srcset="{{img_url feature_image size="s"}} 300w,
{{img_url feature_image size="m"}} 600w,
{{img_url feature_image size="l"}} 1000w,
{{img_url feature_image size="xl"}} 2000w"
sizes="(min-width: 1400px) 1400px, 92vw"
src="{{img_url feature_image size="xl"}}"
alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
>
</picture>
```
refs https://github.com/TryGhost/Team/issues/1680
- paywall card in Admin now inserts cta and restricts content for newsletters as well
- mimics paywall behavior in posts for newsletters
fixes https://github.com/TryGhost/Toolbox/issues/150
- up until now, the test framework has copied all theme fixtures to the
test directory when it boots Ghost
- the vast majority of tests don't need all the themes, so this is quite
a wasteful operation
- this commit disables copying all themes by default, and provides the
`copyThemes` boot option to enable this
- also adds a `copySettings` option, and defaults `redirectsFile` to
false to further reduce the number of file copies
refs https://github.com/TryGhost/Team/issues/1680
- using test emails via email preview in admin were failing due to missing post data attached to them
- adds test to make sure email segment rendering doesn't crash even with missing data
refs https://github.com/TryGhost/Team/issues/1695
This property can be used by theme developers to determine if comments
are available for the currently logged in member. It follows the same
logic as used internally in the comments helper, so that they can be
used interchangeably
refs https://github.com/TryGhost/Team/issues/1695
This updates the comments helper based on the design document
Changes include:
- `color_scheme` renamed to `mode`
- `avatar_saturation` renamed to `saturation`
- `saturation` default changed from 50 to 60
- `count` option added
- `title` option added
The count and title options allow theme developers to better customise
the output of comments, so that they can either pass in their own
title, or pass in no title, and instead provide HTML in the them to
handle it. The same is the case for the count option, which is used to
toggle whether or not the comment count is shown.
refs https://github.com/TryGhost/Team/issues/1705
- Made `max-width` smaller to avoid super-long lines
- Added `span` elements with `nowrap` to avoid one or two-word orphans
Co-authored-by: Rishabh <zrishabhgarg@gmail.com>
refs https://github.com/TryGhost/Team/issues/1688
We've moved the BREAD logic out of the endpoint and into a controller which
interfaces with the `frame` object from our API framework. The service handles
the core logic of comments, and has been updated with several fixes. This
separation means we keep the HTTP API logic and the underlying comments logic
decoupled.
We've also updated the naming to make it clear that it is part of the members api.
Permissions have been implemented, ensuring that members cannot create comments
if they do not have the required access, but they are able to edit their existing comments,
regardless of access.
The edited_at field is now correctly updated when a comment is edited.
- these agent files are all very similar and should be grouped together
- moving them into a subfolder makes the `test/utils` folder a little
bit easier to browse
- we keep seeing random failures that complain about a directory already
existing when trying to create it
- the error arises from the `fs.copySync` in this `prepareContentFolder`
function, because it tries to create the folder if it doesn't exist
- it turns out we're using the asynchronous `fs.ensureDir` without an
await just before, so it doesn't block on creating the folder
- there's a veeeery small window where the code within `copySync` thinks
the folder doesn't exist, `ensureDir` creates the folder, and
then `copySync` tries to create the folder => 💥
- it looks like we're already `await`-ing `prepareContentFolder`, so we
can just switch all the calls to the Promise-based ones and await them
- the other `prepareContentFolder` uses the sync versions of the
functions, but we can fix that in the future: 7b7767d483/ghost/core/test/utils/e2e-utils.js (L73-L79)
refs TryGhost/Team#1680
- extends the public preview card so that the paywall is shown in newsletters for paid-only posts based on member's access
- adds CTA for paywalled content in newsletters
- the segmentation for paywall only considers free and non-free members, so post with specific `tiers` and `paid-only` access settings are sent to all paid members
Co-authored-by: Djordje Vlaisavljevic <dzvlais@gmail.com>
refs https://github.com/TryGhost/Team/issues/1719
- creates scripts injected for portal/search/comments using new config format
- adds `data-styles` to search/comments script for adding external styles URL
refs https://github.com/TryGhost/Team/issues/1709
- New event type `comment_event` (comments and replies of a member in the activity feed)
- Includes member, post and parent relation by default
- Added new output mapper for ActivityFeed events
**Changes to `Comment` model:**
* **Only limit comment fetched to root comments when not authenticated as a user:**
`enforcedFilters` is applied to all queries, which is a problem because for the activity feed we also need to fetch comments which have a parent_id that is not null (`Member x replied to a comment`). The current filter in the model is specifically for the members API, not the admin API (so checking the user should fix that, not sure if that is a good pattern but couldn’t find a better alternative).
* **Only set default relations for comments when withRelated is empty or not set:**
`defaultRelations`: Right now, for every fetch it would force all these relations. But we don’t need all those relations for the activity feed; So I updated the pattern to only set the default relations when it is empty (which we also do on a couple of other places and seems like a good pattern). I also updated the comments-ui frontend to not send ?include
refs https://github.com/TryGhost/Team/issues/1717
- Updates last_commented_at and last_seen_at (only once a day)
- Used the LastSeenAtUpdater, so we can combine updating last_commented_at and last_seen_at in one query + used same pattern
- Updated comments service to await emails in order to make E2E tests more stable (as we don't have any method to await emails and test emails otherwise). This removed the email sending logic from the `onCreated` hook of the model.
fixes https://github.com/TryGhost/Team/issues/1718
- Text content of report emails still had some placeholder text
- Converts HTML comments to TXT to include in the TXT version of the email
- Added support for Regexp matchers in the email mocker
- Added tests to check if the email content is in the new comment/report emails
refs https://github.com/TryGhost/Team/issues/1688
* Added missing/failing tests
* Refactored comments BREAD into service
* Ensured member_id is not writable, it should come from auth only
* Ensured one cannot reply to a reply
* Ensured the parent_id is not writable on edit
refs https://github.com/TryGhost/Toolbox/issues/357
- One time jobs need a storage mechanism to be run only ever once.
- Field notes:
- `id`, `created_at`, `updated_at` - standard Ghost fields
- `name` - unique name of the job, could also be used with prefixing to identify certain type of job (e.g.: backup-bob-2022-10-16, backup-sam-2023-01-13 identifying backup jobs run by users)
- `status` - 'started' | 'finished' | 'failed' | 'queued' (need to identify when the job is in progress, done, added to the execution queue, or errored)
- `started_at` - when the job started execution
- `finished_at` - when the job successfully finished execution
closes https://github.com/TryGhost/Team/issues/1684
**Migrations:**
- Added report permissions (fixtures + migrations)
- Dropped reason field in reports (no textarea in reports in V1)
- Dropped nullable from comment_likes.member_id (can't be null)
- Added SET NULL/CASCADE foreign keys for comments related tables(*)
(*):
fixes https://github.com/TryGhost/Team/issues/1687
refs https://ghost.slack.com/archives/C02G9E68C/p1658217288591369
This commit adds support for `SET NULL` foreign keys in schema and migration helpers + also fixes the foreign keys for the comment_reports, comment_likes and comments tables.
- When a member is deleted, we **do** want to keep their reports (SET NULL)
- When a member is deleted, we **do not** want to keep their likes (CASCADE)
- When a member is deleted, we **do** want to keep the comments (SET NULL)
**Changes:**
- Added report API: `POST /members/api/comments/{id}}/report/`
- Sends an email to the owner when a comment is reported
- Saves a report to the database (not used for now, but might be useful later)
refs https://github.com/TryGhost/Toolbox/issues/354
- this commit turns the Ghost repo into a monorepo so we can bring our
internal packages back in, which makes life easier when working on
Ghost