refs #10318
Because settings are not populated with the correct group and flags, we
must _always_ set these. Then we can check to see if there are values
which need migrating, and if not, can safely exit and leave the values
as default.
refs #10318
If migrating from a previous version that does not include the setting
being migrated from we can safely not update the new setting, and just
rely on its default value being present. When rolling back we can use
defaults if the new setting does not exist.
closes#11936
- the driving reason for doing this is so that when posts and taxonomies all have the same route,
e.g. /:slug/ the /edit route won't default to looking up tags
this is the issue outlined in #11936
- the side effect of this is that in this case, all routes will default to looking up posts before tags,
so if you have a /test/ post and a /test/ tag, prior to this change, the tag would have been loaded first
but posts are more important than tags, and should have higher priority, so this change is considered correct
refs https://github.com/TryGhost/Ghost/issues/10318
- Updates the type field for a setting to specify its type explicitly
- Type can be one of (string, number, boolean, array)
- `object` is allowed a temp type till all the object settings are removed
- existing `type` value for setting was misleading and referring to `group`
- we moved the current `type` value for a setting to `group` here - 4a9e57c170
v3.21.1
* tag '3.21.1':
v3.21.1
Updated Ghost-Admin to v3.21.1
Un-skipped populateImageSizes subdir test
Fixed unit tests interdependency issue
Fixed `populateImageSizes` handling of images in subdir setups
🐛 Fixed potentially squashed images in image cards
Refactored site url data attribute for new members script
* Updated members default settings
ref #10318
This pulls out the members_subscription_settings & stripe_connect_intgration settings into separate keys
* Updated usage of members_from_address
* Updated stripe_connect usage
* Updated members config to use new settings
* Updated members middleware to use isStripeConnected
* Updated members service to reload correctly
We reload the members-api instance when the related settings change, so
this makes sure we're listening to the correct settings changes
* Updated ghost_head helper to use new settings
* Updated theme middleware to use new settings
* Renamed members_allow_signup -> members_allow_free_signup
* Fixed tests after settings refactor
* Removed from direct key settings key
* Fixed regression tests for settings api
refs #10318
As populateDefaults is run _before_ migrations, the new settings will
already be inserted in the database, so we just need to update their
values and then delete the old settings.
refs https://github.com/TryGhost/Ghost/issues/10318
`Settings.populateDefaults()` is run before migrations during Ghost's startup. This can cause problems when new settings table columns are added (and populated in `default-settings.json`) because `populateDefaults()` was using the model layer which assumes that those columns are available, resulting in `ER_BAD_FIELD_ERROR: Unknown column` type errors.
- query the database for the available `settings` table columns
- switch to using raw knex queries without Bookshelf for insertions so that we're in control of the columns that are added
- use `_.pick` to skip any properties in `default-settings.json` that do not match to an available column - those columns will be added and populated by later migrations
- moving away from using the model to insert settings has the side-effect of not emitting `settings.added/edited` and `settings.x.added/edited` events, this should be fine because `populateDefaults()` is called before anything else is set up and listening
- added a call to `populateDefaults()` in our knex-migrator "before migration" hook so that we have consistent db state across both startup initialised migrations and manually triggered knex migrations
no issue
- Import error grouping wasn't working correctly when error didn't have defined context property
- The copy will be refined in final design review
no issue
- when using subdirectories, images can be stored in the database both with and without the subdirectory prefix. We weren't taking that into account and so images without the subdirectory were not having the `/content/images/` prefix removed when passed to the storage adapter resulting in the storage adapter not finding the image
refs https://github.com/TryGhost/members.js/issues/54
- Previously new meta tag was added which defined the site url which was used by new script
- Removes meta tag and instead directly uses a data attribute defined on script tag which it can read on load, making it much simpler
no-issue
These utils are the first steps toward getting the models out of our
migrations! The utils here interact directly with the database and where
possible don't reinvent the wheel, by using smaller building blocks to
build more comples ones.
refs TryGhost/Ghost#10318
refs 8fc526ff6
- This is symetric change to one done for v3 API (commited as 8fc526ff6)
- Added 'core' filtering for v2 API controller
refs https://github.com/TryGhost/Ghost/issues/10318
- `shared_views` is always an array (Ghost-Admin has handling to revert it to an array if it's anything else) but it's default value was set to an empty object
refs https://github.com/TryGhost/Ghost/issues/10318
- `members_public_key` and `members_private_key` are now correctly grouped under `core` which is already filtered out so we don't need the extra filter to exclude them
refs https://github.com/TryGhost/Ghost/issues/10318
refs 1dc0405803
- Adds 1:1 mapping for filtering options to renamed settings "type" to "gorup"
- Ignores the name changes and any old types
- Detailsed type -> group mappings can be checked in the refereneced migration commit
refs https://github.com/TryGhost/Ghost/issues/10318
- maps old `settings.type` values to new `settings.type/group` values
- uses an explicit map so that we don't lose information and can safely roll back even though we're modifying `settings.type` too
- updates `settings.type` values too to keep code working while we switch to using `settings.group`
- sets the `settings.group` value for all settings which are keeping the same group as their current type
- adapts `settings.type` validations to match new groups
- adds flags to specific settings, both in the migration for existing settings records and in default-settings.json for new settings records
refs https://github.com/TryGhost/Ghost/issues/10318
- `group`
- to replace the `type` column, provides a more descriptive name for the columns use
- for existing sites it will be populated by migrating data from the `type` column in a later migration
- for new sites a minimal update has been added to `parseDefaultSettings()` to populate the `group` field when settings are created during startup - fixes the NOT NULL constraint on `settings.group`
- `flags`
- signifies special handling that is different to other settings in a group
- eg, `PUBLIC,RO` would indicate that the setting is available via unauthenticated endpoints and is read-only
refs https://github.com/TryGhost/Ghost/issues/10318
- There was a copy/paste error and we didn't have a test to pick it up. Will follow up with a regression test to make sure it doesn't happen again
refs #10318
refs 2614565d5a
- Adds importer mapping for fields as in referenced migration
- The intention is to allow exports from v2/v3 to still be compatilbe with current version
- Adds a mapper for deprecated fields and imports them with new settings "keys"
refs #10318
refs 2614565d5a
- Renamed ghost_head/ghost_foot in settings to match the new names
introduced in migrations
- Above change lead to reshufling in the mappings in input/output
serializers
- Makes sure change is compatible with v2 API
refs https://github.com/TryGhost/Ghost/issues/10318
refs 2614565d5a
- Renames to match referenced migration renames
- Fixed API responses so they are consistent with newly renamed fields
- Not returning lang and timezone keys from settings in API v2 ther rest should be returned in API v3/canary
refs https://github.com/TryGhost/Ghost/issues/10318
- precursor to migrating from `settings.type` to `settings.group`
- renames `blog` type to `site`
- renames `bulk_email` type to `email`
- moves settings out of `site` (previously `blog`) into more appropriate groups such as `core` or individual feature groups
no issue
- Previous migration in commit - 2614565d5a - was using incorrect json structure for brand -> primary_color
- Fixes the up/down migrations to work on correct existing `brand: primary_color` structure
refs https://github.com/TryGhost/Ghost/issues/10318
- Adds following renames to settings table keys:
'default_locale' -> 'lang'
'active_timezone' -> 'timezone'
'ghost_head' -> 'codeinjection_head'
'ghost_foot' -> 'codeinjection_foot'
'brand.publicationColor' -> 'accent_color'
- The renames are done to match revised naming conventions and naming
exposed through APIs
- Supersedes this revert - 1eeb5a60b8 and #11946
no issue
- when using subdirectories, images can be stored in the database both with and without the subdirectory prefix. We weren't taking that into account and so images without the subdirectory were not having the `/content/images/` prefix removed when passed to the storage adapter resulting in the storage adapter not finding the image
refs https://github.com/TryGhost/Ghost/issues/10318
- Adds following renames to settings table keys:
'default_locale' -> 'lang'
'active_timezone' -> 'timezone'
'ghost_head' -> 'codeinjection_head'
'ghost_foot' -> 'codeinjection_foot'
'brand.publicationColor' -> 'accent_color'
- The renames are done to match revised naming conventions and naming
exposed through APIs
refs #10318
refs https://github.com/TryGhost/Ghost/pull/11942
- Removes force_i18n, permalinks, and members_session_secret usage from the codebase
- We deprecated these flasgs and have not used since Ghost v2. It's good time to remove them before we introduce bigger changes to how `settings` table opeartes.
- Fixed importer test. The test was meant to check if string values were converted properly, the check agains boolean didn't make much sense in this context, so removed it.
- Following this change are going to come ralated migrations to fix existing data (see ref)
refs https://github.com/TryGhost/members.js/issues/54
- Previously new meta tag was added which defined the site url which was used by new script
- Removes meta tag and instead directly uses a data attribute defined on script tag which it can read on load, making it much simpler
no issue
- reverts commit 87c31444fd but with modifications to settings naming
- Adds new settings for members modal customization to default settings
- `portal_button` controls the visibility of beacon in members modal
- `portal_name` controls the visibility of name field in signup
- `portal_plans` controls the visibility of plans allowed for member to signup with
- Adds stripe connect check to determine if stripe is setup or not
- Adds the 3 new settings to members site data
- Updates to snake case naming for members site API data
no issue
- Moves out CSV parsing and serialization related code into separate package as a part of push to modularize Ghost repo.
- Next up is to remove `csv-parser` dependency from this new package
refs 7904c303a7
- Model's validation errors are sometimes returned as an array of errors, in those cases they should be flattened to before returning to the client. This way there is more insight into what went wrong during the import.
no-issue
pr: https://github.com/TryGhost/Ghost/pull/11930
- Upgraded @tryghost/members-api to 0.23.0
This version includes a new method hasActiveStripeSubscriptions
- Added /admin/members/hasActiveStripeSubscriptions
This can be used to determine whether or not we should allow removing
the stripe keys.
- Added /admin/settings/stripe/connect
This can be used to delete a Stripe Connect integration, provided
there are not active subscriptions
no issue
- fixed incorrect method name when calling
- fixed problem with setting post.mobiledoc to a promise rather than waiting for the size population to finish and setting it to a mobiledoc string
no issue
- `?formats` is useful when you want to get `html` back from the Admin API when creating/editing posts, otherwise you're forced to make a following `GET` request
no issue
- Adds new settings for members modal customization to default settings
- `membersjs_show_beacon` controls the visibility of beacon in members modal
- `membersjs_show_signup_name` controls the visibility of name field in signup
- `membersjs_allowed_plans` controls the visibility of plans allowed for member to signup with
- Adds stripe connect check to determine if stripe is setup or not
- Adds the 3 new settings to members site data
no issue
- adds `populateImageSizes()` to our mobiledoc lib module
- uses `image-size` lib to speed up reading of image dimensions
- for local images, use storage adapter with same guards as used by `handle-image-sizes` middleware so that we don't insert srcsets for images that aren't transformable
- for unsplash images, remove any width and crop params from the url so it points to the full-size image
- use `populateImageSizes(mobiledoc)` to modify post model's mobiledoc when re-rendering
no issue
- known failing case was Medium. Some *.medium.com articles triggered redirects but without cookies being stored/sent across the redirect requests it would cause an infinite redirect loop and we'd abort after 10 redirects
- use `got`'s [cookie support](https://github.com/sindresorhus/got/tree/v9.6.0#cookies) via `tough-cookie` so that we can create bookmark cards for medium.com and other sites with similar problems
- There were various cases where it was possible to trigger a private site to display a 404 instead of redirecting to /private/
- Private mode was also not always displaying the correct robots.txt
- This PR includes tests for all cases in test/frontend-acceptance/default_routes_spec.js & where possible the unit tests have also been updated for completeness
- Fixing the 404 issues required
- Better handling of paths using req.path instead of req.url in filterPrivateRoutes
- Additional error handling, to cover the case that a tag/author RSS feed does not exist
- Fixing the robots.txt required the order of middleware to be changed, so that private blogging gets a chance to render first
- NOTE private blogging is the only app with a setupMiddleware function so nothing else is affected
no-issue
This issue only occurs when using custom redirects with a subdirectory
setup, and the path to be redirected from is expressed as a regex, and
the url that is being redirected to is not an external url.
The issue has a few components:
- Redirect paths as a regex generally use the ^ to ensure that they
match the beginning of the path.
- The path that the regex is matched against conditionally excludes the
subdirectory, specifically, the subdirectory is excluded for external
urls
These combined means you end up with a regex like /^\/custom-redirect/
and a path like /subdir/custom-redirect, these will not match/replace
correctly, and you'll end in an infinite redirect loop.
The fix here is to *always* remove the subdirectory when testing regex's
and then conditionally adding it back *only* for the redirect, and only
if it is an internal redirect
This is a bunch of small changes, that simplifies working with the private blogging module:
- remove reference to really old paginated RSS behaviour
- remove handling for /rss and allow our standard redirects to redirect to /rss/ and then execute
- readd should to tests so that they can be run standalone
- fix eslint warning
no issue
- localhost check was causing an immediate "no provider" error when fetching oembed for a localhost url and bypassing the bookmark fallback even when the configured site lives on localhost
- allow `localhost:port` through in oembed endpoints when it matches the configured url
no issue
- pass `srcsets` value through to mobiledoc renderer
- it will stop adding `srcset` attributes to images when explicitly set to `false`
- adds `reload()` method to `mobiledocLib` so that memoized instances of the renderer can be reset during tests that change config values
closes#11917
- Pass text-only version to mailgun as `text` not `plaintext`
- This ensures we send a text-only version of the email, and this in turn should help to improve spam scores
refs https://github.com/TryGhost/Ghost/issues/11414
- Importing data currently overwrites the existing "from address" with new value
- "from address" needs to go through email validation flow before update which was bypassed
- Updates importer to not allow overwrite for "from address" and use existing
- Adds test for "from address" overwrite
- We have many customers asking for INR as there are special rules in Stripe for this currency
- As well as a desire for local-selling
- Meaning it's not valid to use e.g. USD instead
no-issue
This was initially missed as local settings always had the original
stripeDirect keys, this ensures that regardless of Connect vs Direct vs
Both vs Neither that the config is correct.
Also ensures that the Members API instance is reloaded when the Stripe
Connect settings are changed.
no issue
- there are various situations where we adapt/fix/improve our mobiledoc->html output over time but we didn't have a way of updating old content without manually editing the mobiledoc and saving, or running an expensive migration to re-render all old content
- this adds a `?force_rerender=true` query param to the `PUT .../admin/posts/:id/` endpoint that allows the `html` field to be re-generated without modifying the `mobiledoc` field contents
no issue
- The intention is to move away from using file type names in URLs. This endpoint is meant to correspond to current `POST /members/csv` endpoint, that is planned to be renamed into `/members/upload`. And the `GET /members/csv` to be renamed to `/members/download` respectively.
refs TryGhost/members.js#39
Currently, there is no way to determine exact Ghost site url from a theme, which is used by new members.js to initialize the script and use members/admin API. This change
- adds a new meta tag - `ghost:site` with value as ghost site url, when members is enabled
- new meta tag is behind dev flag along with members.js script
no issue
- NQL does not support the relationship setup that members->stripe customer<->stripe subscriptions uses so it wasn't possible to use the `filter` param to query against having an active subscription
- adds `customQuery` bookshelf plugin that allows customisation of SQL query used in `findPage` method by individual models
- use `customQuery` in Member model to set up joins and conditionals to select free/paid members when `options.paid` is present
- allow `?paid` param through API and permitted options for member model
no issue
- This new format allows to return additional metadata with failed import records. The data for invalid records is returned in following format:
```
{
count: {count_of_invalid_records},
errors: [{
message: "Members not imported. Members with duplicate Stripe customer ids are not allowed." // message field of the error
context: "Attempting to import members with duplicate Stripe customer ids." // context field of the error
help: "Remove duplicate Stripe customer ids from the import file, and re-run the import." // help field of the error
count: 2 // count of this specific error
}]
};
- Errors are grouped by their context fields because message fields sometimes can contain unique information like Stripe customer id, which would produce too many errors in case of bigger datasets.
no issue
- This endpoint is meant to be used for validation of imported members
- Main function at the moment is to validate if stripe_customer_id present in the dataset exists in connected Stripe account
no-issue
We had a circular dependency issue when using the members service, so
this commit replaces the use of that with a check to the settings cache
to check if stripe connect has been setup.
no issue
- Ghost-Admin redirects all paths to `/ghost/settings...` as `/ghost/#/settings/...`, this updates the admin redirect on successful magic link validation to directly use the latter to avoid extra redirect
no issue
- adds a set of hardcoded "content image sizes" to the base config
- adjusts `handle-image-sizes` middleware to always allow the hardcoded content image sizes to be genreated
- updates `@tryghost/kg-card-factory` to allow passthrough of options to card renderers
- updates `@tryghost/kg-default-cards` to add `srcset` output for image and gallery cards
closes#11008
- Updated @nexes/nql to 0.4.0
This version exports the mapKeyValues utility function
- Replaced nql-map-key-values with @nexes/nql util fn
Usage was found using `rg nql-map-key-values` and replaced globally.
- Deleted nql-map-key-values module in shared
Now that this module isn't referenced anywhere else, we can remove it,
relying solely on the util exported by @nexes/nql
refs https://github.com/TryGhost/members.js/issues/43
- Adds new `isStripeConfigured` flag to public members site data which denotes if stripe setup is completed
- Helps clients like members.js/themes to configure payment behavior based on this flag
no-issue
The service at stripe.ghost.org must know which client_secret to use,
either the test, or live one. By encoding a JSON object as the state we
are able to pass data through the flow to inform this decision at the
end.
Note, that we still keep a random value in the state to protect against
CSRF attacks.
no-issue
We've added a "mode" query param to the members_stripe_connect api auth
method, allowing the client to easily switch between live and test mode.
no-issue
This adds the ability to pass a `mode` param of 'test' to the members stripe
connect service, which will ensure we use a testmode client_id for the
Stripe Connect OAuth flow.
This will allow users to connect their account in testmode.
no issue
- When imported member contains stripe_customer_id data but there is no Stripe configured on the Ghost instance such import should faiil. The logic is consistent with one where import fails after not being able to find customer in linked Stripe account
- Fixed import stats to show import failures instead of "duplicate" when the validation error is of "Stripe" origin
no issue
- The aim was to extract format-csv to become an external dependency. After some analysis found out that native papaparse method `unparse` was achieving the same results with a lot better test coverage and stability. Because papaparse will become Ghost's default csv processor in near future decided to integrate papaparse instead of extracting module for the format-csv module's code, which would become redundant soon anyways.
- For reference papaparse will substitute current csv-parser lib because it's better performance and maturity.
- Performance comparison can be checked here - https://github.com/Keyang/csvbench#result . At the time of writing papaparse is rougly 40% faster than csv-parser
refs https://github.com/TryGhost/Ghost/pull/11807
- this was originally reported in the PR above, but we could not
reproduce it on master
- presumably the user had the latest version of moment installed for
other purposes and so they were seeing the issue
- between moment 2.24.0 and 2.26.0, something must have changed which
stopped the previous functionality working
refs https://github.com/TryGhost/Ghost/issues/11414
Confirms if the fromAddress for sending member emails is valid and accessible using magic link flow, allowing owners to update full from address including domain change.
- Extends member service to handle magic link generation and validation for email update
- Updates existing setting endpoint to not directly update from address
- Adds new endpoint to send magic link to new address
- Adds new endpoint for validating the magic link when clicked and update the new email for from address
- Adds new email template for from address update email
refs https://github.com/TryGhost/Ghost/issues/11414
We want to allow adding custom domains to member's from address as long as the new email is verified using the magic link flow and not saved directly to DB. Since we currently don't store domain as part of fromAddress, this PR -
- adds migration to update all existing fromAddress by appending site domain
closes https://github.com/TryGhost/Ghost/issues/11768
- Wraps from parameter in double quotes so mail clients can read it whole
- Escapes double quotes in site title to avoid clash with wrapping
- Currently theme uploads delete the existing theme before copying the new files into place
- If something goes wrong with the delete action, you will end up in a bad state
- Some or all of the files may be deleted, but now Ghost won't try to put the new theme in place, instead returning an error
- This leaves you with an invalid active theme and a broken site
- Unlike delete, move is a one-hit operation that succeeds or fails, there moving a theme is safer than deleting
- This updated code moves the old theme to a folder with the name [theme-name]-[uuid] before copying the new theme into place
- Even if this fails, the files should not be gone
- There's a cleanup operation to remove the theme backup at the end, but we don't care too much if this fails
refs https://github.com/TryGhost/Ghost/issues/11212
- if a bookmark card fetch is performed (either directly or from fallback) and the page does not have an extractable title, return a more specific error message than "No provider found for supplied URL."
no issue
- When the customer cannot be imported because they are missing from linked Stripe account or the linked account is incorrect one, these new messages should provide a better clue about what has caused the error and how to act on it.
no issue
- There is a need to be able to label certain import group of members
with custom labels. This will allow to distinguish/filter these newly
imported members.
- Allowed `POST /members/csv/` endpoint to accept `labels`
field parameter which assigns labels to every member from imported csv.
no issue
- Similarly to other additive api methods (e.g. members.add) returned more specific ValidationError with contex filled in with the reason why adding did not succed.
- This change is needed for more graceful label handling when adding new members through import
no issue
- Adding labels doesn't cause any content to invalidate, similarly to adding members. Unlike it's caunterpart - tags, there is no dependent "frontend" content that would become invalid
no-issue
This was because the API was recieving a default `null` value for the
stripe_connect_integration_token setting.
This also improves the logging for this error.
no issue
- added an `externalRequest` lib
- uses same underlying `got` module as our `request` lib
- uses `got`'s `beforeRequest` and `beforeRedirect` hooks to perform it's own dns resolution for each url that's encountered and aborts with an error if it resolves to a private IP address block
- includes a bypass for Ghost's configured url so that requests to it's own hostname+port are not blocked
- updated v2 and canary oembed controllers to use the `externalRequest` lib
no-issue
If the stripeDirect config value is NOT set / false, then connect token
should be used over the API keys if both are present, or else use
whichever is present. If the stripeDirect config value is set /
true,then API keys should be used and stripe connect token should be
completely ignored.
The reason for this is that we want to use Stripe Connect as the primary
auth method going forward, but we want to keep the direct version
availiable should the Ghost Foundation ever dismantle. This will allow
people to use all the same features with no dependency on an external
service.
no-issue
In order to issue a redirect we need access to the "raw" req/res
objects, which is why we must return the function which gets access to
them.
The members service is used to create the auth url and to update the
users session.
no-issue
Uses the members service to parse a stripe_connect_integration_token
setting and set the stripe_connect_integration based on that.
This change includes ignoring the stripe_connect_integration{,_token}
settings, as the token is never saved, and the integration can only be
set by using the token.
no-issue
This module handles the creation of a url used for authorization of
Stripe Connect, and also the parsing of the data eventually received
from the authorization flow.
no-issue
There was some unused code here, the variable was never used, also we
were looping and collecting a list of errors, but only every using the
first one, so switched to the `find` method which stops iteration after
an element has matched.
closes https://github.com/TryGhost/Ghost/issues/11841
- Migration adds mapping between permissions and roles for email_preview send test mail
- Only owner previously had correct permission to send test emails
- Fixture existed to allow Admin/Editor/Integrations to send test mails but had missing migration
- Adds tests for roles to send test email
refs https://github.com/TryGhost/members.js/issues/30
- Added new `updateEmail` type for sending email address update confirmation mail to member
- The link in email updates member's email address
no issue
- in the near future, non-Ghost Ignition type errors will be coming into
Sentry
- because they don't have a statusCode, they'll be rejected
- we want to detect if they're non-Ghost and still deal with them
no issue
- node was complaining the package was missing after the sanitize-html update [1]
- the update removed an old version of lodash which supported the dot importing
method
- our code relied on this subdependency to work, but the structure has since
been updated
[1]: https://github.com/TryGhost/Ghost/pull/11867
- Ghost Admin has a redirect system built in, so not using the # does work
- However, the usage of # or no # was inconsistent, which is always wrong
- Using the correct Ghost Admin URLs makes it easier to reason about the behaviour
closes#11762
- iframe embeds which include a line break were undetected by the regex which checks for the existence and injects the required amp script
- this fix updates the regex to include any non-word character, as line-breaks are not included in the general `.` token
- Represents that logging is shared across all parts of Ghost at present
* moved core/server/lib/common/logging to core/shared/logging
* updated logging path for generic imports
* updated migration and schema imports of logging
* updated tests and index logging import
* 🔥 removed logging from common module
* fixed tests
refs https://github.com/TryGhost/members.js/issues/36
- Replaces existing members.js with new script which covers existing functionality as well as adds new ones
- This is behind developer experiments flag atm
refs https://github.com/TryGhost/members.js/issues/30
- Member cannot update their email directly but need to do it via magic link sent to new email address
- Previous profile update change had allowed email to be updated directly as well for authenticated member
no issue
- adds `search` bookshelf plugin that calls out to an optional `searchQuery()` method on individual models to apply model-specific SQL conditions to queries
- updated the base model's `findPage()` method to use the search plugin within `findPage` calls
- added a `searchQuery` method to the `member` model that performs a basic `LIKE %query%` for both `name` and `email` columns
- allowed the `?search=` parameter to pass through in the `options` object for member browse requests
* moved `server/config` to `shared/config`
* updated config import paths in server to use shared
* updated config import paths in frontend to use shared
* updated config import paths in test to use shared
* updated config import paths in root to use shared
* trigger regression tests
* of course the rebase broke tests
* refactored core/frontend/services/proxy to import common dependency like a normal person
* removed all imports of `common/errors`
* 🔥 removed common/errors module
Co-authored-by: Vikas Potluri <vikaspotluri123.github@gmail.com>
no issue
- moves members stats generation for the admin graph from the client to the server
- outputs a basic totals count across a requested date range of 30, 90, 365 days, or all time. See below for the response shape
- leaves heavy lifting of the counts to the SQL engines - tested on a dataset of 100k members and query performance is <100ms
```
GET /ghost/api/canary/members/stats/?days=30
{
total: 100000,
total_in_range: 20000,
total_on_date: {
'2020-04-25': 19000,
'2020-04-26': 19500,
// continues until today's date
},
new_today: 200
}
```
* refactored `core/frontend/apps` to destructure common imports
* refactored `core/frontend/services/{apps, redirects, routing}` to destructure common imports
* refactored `core/frontend/services/settings` to destructure common imports
* refactored remaining `core/frontend/services` to destructure common imports
* refactored `core/server/adapters` to destructure common imports
* refactored `core/server/data/{db, exporter, schema, validation}` to destructure common imports
* refactored `core/server/data/importer` to destructure common imports
* refactored `core/server/models/{base, plugins, relations}` to destructure common imports
* refactored remaining `core/server/models` to destructure common imports
* refactored `core/server/api/canary/utils/serializers/output` to destructure common imports
* refactored remaining `core/server/api/canary/utils` to destructure common imports
* refactored remaining `core/server/api/canary` to destructure common imports
* refactored `core/server/api/shared` to destructure common imports
* refactored `core/server/api/v2/utils` to destructure common imports
* refactored remaining `core/server/api/v2` to destructure common imports
* refactored `core/frontend/meta` to destructure common imports
* fixed some tests referencing `common.errors` instead of `@tryghost/errors`
- Not all of them need to be updated; only updating the ones that are
causing failures
* fixed errors import being shadowed by local scope
no issue
- Removes global bodyParser middleware for membersApp and adds it to specific endpoints
- Removes global boolParser middleware for membersApp
We added bodayParser middleware to memebrsApp in [this](fe3eab1836) commit to read json requests for members update endpoint, but that had issues with stripe webhook parsing for `/webhooks` endpoint as stripe expects raw data to be passed down.
no issue
- updated `filter` plugin with appropriate label relationship and replacement config for NQL
- fleshed out member and label fixture data and tools to facilitate tests
no-issue
The flag currently defaults to `true` as we are still using stripe
direct. We expose it on the admin api config endpoint so that the
Ghost-Admin client can use it to conditionally render
- Allows member logged in with valid session to update their profile info - name, email, subscribed(newsletter subscription status)
- Adds new util method for formatted member response on the endpoints
- Adds common middlewares for body/bool parser and maintenance
- Adds `subscribed` status to member response
no issue
- shows the full URL instead of a truncated link in password reset email body. This is required for security and usability reasons (copy/paste)
closes#11304
- Google requires an `ImageObject` to be always returned for `publisher.logo` (https://developers.google.com/search/docs/data-types/article)
- The previous fix 3f5daa60c8 added a second nested `url` error and got therefore reverted with 7ac614030d
- This commit updates the image object generation fn to **always** return an `ImageObject` with minimum of `url` and `@type` properties. If dimensions are available, we'll pass those in there as well
closes#11825
- The initial implementation had a typo in a role name which didn't allow "Administrator" to edit post's "visibility" attribute
- Added unit tests to check administrator specific role and visibility attribute permission
closes#11772
- Ensures that isSecondary is a boolean true or false
- Added tests that cover the bug, switching to using compile because the helpers have to be run together
- TODO: all tests for helpers should be switched to compile, it's SO MUCH easier
- Add a query param that indicates whether signin/up succeeded or failed
- Add unit tests for all 3 possible cases for the createSessionFromMagicLink middleware
- Added an acceptance test to show the behaviour works in principle
- This restores the functionality from 3.14 as follows:
/members/ -> (with no route) rendered 404 error
/members/ -> (with route) renders members template
/members/?token=invalidtoken&foo=bar -> redirects to /?foo=bar
/members/?token=validtoken&foo=bar -> redirects to /?foo=bar
refs https://github.com/TryGhost/Ghost/pull/11790
- reduced complexity by sticking to one email for both normal reset and forced reset (locked staff accounts)
- exposed `siteTitle` for use in any email templates
- updated email copy to be suitable for both types of password reset
- Fixed session invalidation for "locked" user
- Currently Ghost API was returning 404 for users having status set to "locked". This lead the user to be stuck in Ghost-Admin with "Rousource Not Found" error message.
- By returning 401 for non-"active" users it allows for the Ghost-Admin to redirect the user to "signin" screen where they would be instructed to reset their password
- Fixed error message returned by session API
- Instead of returning generic 'access' denied message when error happens during `User.check` we want to return more specific error thrown inside of the method, e.g.: 'accountLocked' or 'accountSuspended'
- Fixed messaging for 'accountLocked' i18n, which not corresponds to the
actual UI available to the end user
- Added automatic password reset email to locked users on sign-in
- uses alternative email for required password reset so it's clear that this is a security related reset and not a user-requested reset
- Backported the auto sending of required password reset email to v2 sign-in route
- used by 3rd party clients where the email is necessary for users to know why login is failing
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
no issue
- Adds new endpoint on integration to refresh admin/content api key secret
- Allows owner/admin to refresh their content or admin API keys for an integration via Ghost Admin
- Adds a new `refreshed` event to actions table for anytime an api_key secret is refreshed
- Added a wrapper around express.Router to our shared/express util
- Also export static and _express
- Use this shared util everywhre, meaning express is only used directly in this one file
- ATM this file is mostly an experiment / debug helper, it might be removed again later
- The aim is to have a minimal framework wrapping express that allows us to:
- reduce our usage of express() in favour of Router()
- unify some of our duplicated logic
- fix some structural issues e.g. Sentry
- make it easier to understand the codebase
refs https://github.com/TryGhost/Ghost/issues/11756
- we removed the fixed `width: 600px` to fix gmail scaling but that means we need a new way of creating a 600px centre column in Outlook
refs https://github.com/TryGhost/Ghost/issues/11756
- fixed gmail scaling problems
- the `width: 600px` on `.container` was forcing gmail to always render at 600px wide and then use scaling to resize the email to fit the device width
- for most emails gmail would also apply their own font resizing to compensate so it didn't look _too_ bad
- some emails however would not trigger the font resizing, most notably when posts contained a feature image, which would result in very small text
- removing the fixed `width: 600px` resolves the scaling problem and lets the email be truly responsive
- removed attribute selectors in the media query CSS
- gmail does not support attribute selectors
- attribute selectors used to be necessary for Yahoo Mail but this is no longer the case
- tested using litmus.com for all popular email clients
- Use array destructuring
- Use @tryghost/errors
- Part of the big move towards decoupling, this gives visibility on what's being used where
- Biting off manageable chunks / fixing bits of code I'm refactoring for other reasons
- Meant to cleanup the old api/canary/members earlier, removed now as it's unused
- Also removed all the duplicate references to labs.members in various places
- My codebase-wide replacement of const/let yesterday went one step too far :)
- grunt uglify:prod fails on the use of const
- This file should continue to use var for the time being cos there's plans to upgrade this script already :)
- Clarify that the parent app has 2 distinct parts: backend and frontend
- Frontend app takes members and site apps + the frontend SSL redirect middleware
- Backend app already has admin + API (and the SSL redirect needs significant work)
- There's a lot more to do here, but this increases clarity
- create a new app for the /members/ endpoint
- moved all /members/ routes and middleware onto this app
- helps to separate members and frontend/site logic so we can start to decouple things more
refs https://github.com/TryGhost/Ghost/issues/11756
- updates `@tryghost/kg-default-cards` which includes a VML version of video embed card fallbacks
- fixes play button styling for Yahoo Mail
- adds a minimum height to video embeds so they appear more reasonable when images are not loaded
no issue
We changed the magic link route handling from setting global value to just redirecting to frontend in [this](d8d5d6b7d0 (diff-0d54454fd954b0203a71ec52df4bd4c0R96-R98)) commit, but missed removing `next()` call which attempts to send response again causing Unhandled rejection error. This change simply removes the extra `next()` call
refs #10898
- Execute string replacement on external paths
- Take non-top-level base URLs into consideration (to avoid #10776 dups)
- Added tests for all of the above cases
- Magic link token handling doesn't need to be global, this couples the system to the frontend, which isn't necessary
- Instead, we create a session from the token, and redirect to the frontend
- Move res.locals.members setting into existing middleware function instead of having it separate
- The existing createSessionFromToken was actually doing two things behind the scenes
1. Handling the ?token from the magic link and creating an actual session (mounted globally, which is not necessary)
2. Loading an existing session so that a member is logged in to the frontent
- IMO 1. is part of members, and doesn't need to be global
- IMO 2. is part of the frontend. It does need to be global but should NOT be hidden away behind the token middleware, as it wasn't clear what this was doing
- All var declarations are now const or let as per ES6
- All comma-separated lists / chained declarations are now one declaration per line
- This is for clarity/readability but also made running the var-to-const/let switch smoother
- ESLint rules updated to match
How this was done:
- npm install -g jscodeshift
- git clone https://github.com/cpojer/js-codemod.git
- git clone git@github.com:TryGhost/Ghost.git shallow-ghost
- cd shallow-ghost
- jscodeshift -t ../js-codemod/transforms/unchain-variables.js . -v=2
- jscodeshift -t ../js-codemod/transforms/no-vars.js . -v=2
- yarn
- yarn test
- yarn lint / fix various lint errors (almost all indent) by opening files and saving in vscode
- grunt test-regression
- sorted!
refs core/server/api/canary/oembed.js
- updated `kg-default-cards` to a version that will render a thumbnail and play button overlay for video embed cards when rendering to an email target
- added styling for video embed play button overlays to members email template
no issue
- embed cards now store metadata including thumbnail urls in their payload
- we want to use this metadata to render video cards in emails
- by default oembed endpoints return fairly small thumbnail images that don't look great when blown up
- oembed supports a `maxwidth` query param that will instruct oembed providers to return larger sizes of the content if available
no issue
- Handlebars now throws an Error for misuse errors within the if/unless
helpers, but our error handling checks for a TypeError
- this would skip using an IncorrectUsageError and ends up throwing a GhostError
- this commit removes the TypeError check and switches to using the
Handlebars error message
- Because we want devExperiments enabled when checking out from source, we have a committed config.development.json
- It works, but is a PITA if you want to have some local settings, as they have to be stashed (or get accidentally committed)
- This commit adds `config.local.json` as a local file that anyone can specify in any env, and it will be loaded
- Note that config.[specific env].json will trump it / overwrite it
- But you can still have settings alongside!
- added core/shared to watched folders in grunt
- moved sentry to shared
- moved express initialisation to a shared file
- always set trust proxy + sentry error handler
- use this new express init everywhere, and remove duplicate trust proxy and sentry error handler code
- renamed the parentApp in index.js to ghostApp, to reduce confusion with the layer that is named parentApp
- renamed the adminApp inside of parentApp to backendApp to reflect the fact it's both admin+api
- renamed a bunch more variables there to be backend, rather than admin
- renamed the api index.js file to app.js and created a new index which is an actual index
fixes#11774
- providing data as a list ends up hitting code paths that can't handle
arrays
- this ends up causing an InternalServerError
- this commit checks the input type is an object
- spotted in Sentry
- put brand back, but only if dev experiments is enabled
- put members plans and allowSelfSignup back, but this is temporary as they need to live elsewhere
closes https://github.com/TryGhost/Ghost/issues/11659
- default `moment()` timezone is UTC and we store the `published_at` value in UTC
- fetch the configured timezone and convert the date into that timezone before formatting for inclusion in the email template
The featured post images are distorted in the AMP template. This change adds `object-fit:cover` styling, and thus avoids distortion but allows images to scale.
Fixes#11560
closes#11766, refs 7284227f1
- when we changed from host to hostname, more changed than just using the x-forwarded-host if trusted because express req.hostname does not return the port
- this causes issues with an infinite redirect if you try to set a different admin host with a port
- added a test to demonstrate the case, that didn't fail due to an error in the test logic
- switched from redirecting based on req.hostname to using req.vhost.host which has the correct trusted, requested value that we should rely on
- simplified the comparison logic to explicitly compare host with host
no issue
- the code didn't verify the existance of `timeoutInMS` before using it
- this caused `requestTimeout` to be `undefined`
- this commit adds the extra check so the fallback of 5000ms will be
used
- This code was a little verbose, which made it hard to see what was happening (it still is a bit)
- Used destructuring to reduce the code
- Renamed a few variables
- we had urlRedirects, urlRedirects.adminRedirect and adminRedirects
- all do kinda similar things, but for different contexts so for now I've done a minimal renaming for clarity
- and updated some comments!!
- also removed totally unnecessary if res.isAdmin clause, as we don't use that, and it was never true
- cache-control had some logic in it for private blogging + similar logic exists for members in site/app
- having it in 2 places is weird, and having it inside the mw makes the mw less generic/reusable
- instead of requiring config inside the middleware, we pass config in for the one case where this is used
- fixed tests that didn't test anything 🙈
- Moved normalize image mw from shared to api as it is not shared (except within the API)
- This file is only used in one part of the app, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved upload validation mw from shared to api as it is not shared (except within the API)
- Co-located the code with the upload middleware, as it's small and gives us a nice API of .upload.single and .upload.validation
- This file is only used in one part of the app, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- These two functions have no dependencies and are only used in valiation/upload
- Co-locating the code makes it easier to move
- Exported them with a new module.exports._test pattern - we'll see about whether this is a good idea
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved upload mw from shared to api as it is not shared (except within the API)
- This file is only used in one part of the app, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved update-user-last-seen from shared to api as it is not shared (except within the API)
- This file is only used in one part of the app, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved api cors from shared to api as it is not shared (except within the API)
- This file is only used in one part of the app, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved version-match from shared to api as it is not shared (except within the API)
- This file is only used in one part of the app, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
refs https://github.com/TryGhost/members.js/issues/6
This exposes an endpoint on site url (`/members/ssr/member`) to get member's data in exchange for their session/identity on a theme when they are logged in. It essentially uses the same logic and data which is passed down to theme through handlebar helpers, and is used by members.js script to load member data.
no issue
This adds new public settings - description, logo, brand - and some public member settings - plans, allowSelfSignup to the open site endpoint which will be used by members.js for data initialization
no issue
This allows anyone using members service to fetch public membership plans for a site including currency and monthly/yearly charges. This is currently duplicated from theme service where we create the price helper, but will be cleaned up to keep logic in one single place.
- Moved ghost-locals from shared to parent as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- This allows shared middleware to be unhooked from the parent app
- Moved emit-events from shared to parent as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved log-request from shared to parent as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved request-id from shared to parent as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Have a consistent structure so we can co-locate an app with its own middleware
- This is another small step in sorting out the giant mess that was web/shared/middleware
- Moved serve-public-file from shared to site as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
refs 717567995b
- We should not be using relative URLs inside the admin panel anymore
- Removes a usage of "shared" middleware which isn't truly shared
- Moved handle-image-sizes from shared to site as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved static-theme from shared to site as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved serve-favicon from shared to site as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
- Moved admin-redirects from shared to site as it is not shared
- This file is only used in one place, this updates the code structure to reflect this
- This is one of many similar changes needed to make it easier to refactor to the existing setup
no issue
- the `email.{html,plaintext}` fields are only used to display what was sent in the email so it doesn't make sense to store the mailgun-specific content which can be confusing when viewing in the admin area
- store the raw serialized post content with a basic no-data replacement of replacement strings rather than the output of full data fetching and mailgun transformation
no issue
- fixed plaintext templates being word wrapped and breaking across replacement strings
- updated `postEmailSerializer.serialize` to return the email template plus a replacements array that can be used for creating Mailgun-like recipient variable objects or more straight forward replacement
- updated email-preview API to work with the replacements data to show fallback data when previewing
fixes#11746
- the original fix[1] inadvertently moved the logo object down one level
- this commit moves it back up, and fixes the tests to reflect the
expected format
[1]: 3f5daa60c8
no issue
- with the email replacements feature it's useful to have real member data when sending test emails from the PSM
- if the supplied email address matches a member then that member's data will be used for any replacements
no issue
- in our replacements the member properties are prefixed with `subscriber_` but this wasn't taken into account when requesting data from the member object
no issue
- the value of `mobiledoc` when submitting a page/post via the API must
be JSON, but we don't validate this
- this results in url-utils throwing an error, which ends up being a 500
- this commit adds a custom format to AJV to validate it is valid JSON
- also updates tests with bad JSON - 'a'
no issue
- adjusted mega's post serializer to get full email contents
- fetch `mobiledoc` from the API rather than the pre-rendered `html` and `plaintext`
- re-generate `html` using the mobiledoc renderer with an "email" target so that the email-only card content is included
- re-generate `plaintext` from the newly generated email html
- added replacement handling to mega's `getEmailData` function
- find all of our `%%{replacement "fallback"}%%` instances in the html template and push them into a replacements array with the respective property on the member instance and desired fallback
- transform the replacement for Mailgun compatibility. Mailgun uses `%recipient.variable_name%` for its template variables so we need to replace our custom replacement string with the compatible version. Our replacements system allows for the same replacement (`{subscriber_name}`) to be used multiple times and have different fallbacks, Mailgun doesn't support fallbacks so for each replacement we also need an indexed `variable_name` part so that we can put our fallbacks in the correct place
- perform the same Mailgun template transformation for the plaintext version except we re-use the replacements array to avoid bloating the API request to Mailgun with duplicate template variables for every recipient
- swapped `reduce` for a plain loop for easier readability
refs 183e22e0bf (diff-f3a289058604b2b069d07bb8e2cda60cL39)
- When using the `/edit` route in the end of tag taxonomy redirect was landing on 404 page in Ghost-Admin. For example redirect for `/tags/getting-started/edit/` would redirect to `/#/settings/tags/getting-started`, instead of `/#/tags/getting-started`
- Referenced commit is where the routing in Ghost-Admin was changed from `/settings/tags/:slug/` to `/tags/:slug`
fixes#11740
- there was a discrepancy in the use of `private_blog` within the
code, and `private_block` in the default config
- this commit switches the code to `block` in order to avoid breaking
existing configs
- in 3.13.2 the importer always throws the error "The "path" argument must be of type string. Received an instance of Object"
- this is due to a change in method signature that wasn't accounted for
- added a test to catch similar changes to this code in future
no issue
- browsers now block cross-origin cookies unless they are explicitly set with `SameSite=none` and `Secure=true` options which was preventing the login request made by Ghost-Admin from working
- added an explicit `SameSite=none` option to the private site session cookie
- will only work when the front-end site is served over HTTPS - there's no way to get browsers to accept cross-origin cookies over HTTP
fixes#11723
- when deleting an invite/label/tag/webhook that doesn't
exist, Ghost would throw a 500 error
- this commit catches the NotFoundError
- also rejects from model if nothing was found
- spotted in Sentry
- Having to remember to add files to an index.js is a PITA
- We already have glob as a dependency, so use that
- This requires that the file prev_next be renamed to prev_post, which is what it's called as by default
- next_post is an alias of next_post - so this reflects that more closely
- the helper dir also contained some code used with helpers - utils and helper-helpers?
- the goal here was for helpers to be the only thing in their folder so we can look at moving them out
- all other code has been moved to services/themes for now, which is not the right place either
- services/themes is a catch-all for theme storage, loading, validation, rendering and more, needs to be broken down
- this removes the need to require the proxy inside the helpers/index.js file
- have the helper file define and return it's own labs-enabled-ness
- update the tests to test for the labs flag being unset
no issue
- moved `mobiledoc.renderers.mobiledocHtmlRenderer` to `mobiledoc.mobiledocHtmlRenderer` so that it's easier for the getter to access the parent objects getters
- removed all tests and dependencies that now live in @tryghost/mobiledoc-dom-renderer
- kept the `mobiledocHtmlRenderer` test because that's testing that we've correctly wired up our cards and atoms and the output is what we expect
- The proxy is not a helper, we want the helpers folder to only include helpers
- The proxy is also meant to be the interface to Ghost for the helpers, and we want to enforce that
- This is a small step on the way
no issue
- the blank document we use in Ghost is not specific to the html renderer
- renamed from `structure` to `document` to better represent its intent
- allows for easier extraction of `mobiledocHtmlRenderer`
no issue
- importing an LTS export would cause Ghost to throw a 500 error because
it used InternalServerError.
- an IncorrectUsageError is more applicable here
- this commit also updates the code comment and error message
- note: removed comment about WP exports because the plugin has been updated
to support the v2 & v3 format
- spotted in Sentry
no issue
- added the same 2sec timeout and `Ghost` user-agent header to the `rel="alternate"` oembed request that we use for the initial html page request
no issue
- Knex removed their use of several Bluebird methods, including `return`
- our code used `return`, but mostly to return null after a destroy action
- these uses have been replaced with `.then(() => null)` in order to
continue returning null and to avoid breaking anything
- Allows using the 4-bracket raw block syntax e.g: {{{{raw}}}}{{{{/raw}}}}
- This allows you to include handlebars inside a template that is not compiled and executed
- The common usecase is if you want to include client-side handlebars templates inside server-side ones
no-issue
* Added default for getting origin of request
This function is used to attach the origin of the request to the
session, and later check that requests using the session are coming from
the same origin. This protects us against CSRF attacks as requests in
the browser MUST originate from the same origin on which the user
logged in.
Previously, when we could not determine the origin we would return
null, as a "safety" net.
This updates the function to use a secure and sensible default - which
is the origin of the Ghost-Admin application, and if that's not set -
the origin of the Ghost application.
This will make dealing with magic links simpler as you can not always
guaruntee the existence of these headers when visiting via a hyperlink
* Removed init fns and getters from session service
This simplifies the code here, making it easier to read and maintain
* Moved express-session initialisation to own file
This is complex enough that it deserves its own module
* Added createSessionFromToken to session service
* Wired up the createSessionFromToken middleware
no-issue
This services handles the registration and retrieval of adapters,
it normalises the config to look like:
{
[adapterType]: {
active: adapterName,
[adapterName]: adapterConfig
}
}
no issue
- missing modules required by an adapter weren't flagged up as missing,
but that the entire adapter was missing
- therefore, it was difficult to see what you were missing
- this commit handles the case where a module is missing, and displays
an error
* Refactored SessionStore to use @tryghost/errors
no-issue
* Updated tests to test exposed API
no-issue
This will make refactoring easier, as we only have the "public" contract to maintain
* Refactored session functionality to SessionService
no-issue
This splits the session logic away from the HTTP responding logic,
which will allows us to decouple session creation/modification from the
API. Eventually this can be used to create sessions based on magiclink
style tokens.
* Instantiated and exported the new SessionService
no-issue
* Refactored session middleware to take session service
no-issue
This removes duplication of code and makes the middleware more explicit
that it's just a wrapper around the session service.
* Updated to use external @tryghost/session-service
no-issue
- the proxy should always be used to access other parts of Ghost, including the urlService etc
- use consistent ES6 style for requires
- minimise use of lodash where possible
- remove circular dependency between proxy and template util
- End goal here is to enforce that the only link between helpers + the rest of Ghost is the proxy
- move all test files from core/test to test/
- updated all imports and other references
- all code inside of core/ is then application code
- tests are correctly at the root level
- consistent with other repos/projects
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
fixes#11694
- if the post contained no body, the `.replace` would throw an error
- converted to an if-statement instead of doing `|| ''` because there
would be a floating full-stop
no issue
- moved card definitions to a new library `@tryghost/kg-default-cards`
- moved `createCard` factory function to a new library `@tryghost/kg-card-factory`
- moved image.manipulation lib to a new package called @tryghost/image-transform
- new package has an updated API signature, so the method calls have changed but the underlying code is identical
- removed the optional sharp dependency from Ghost, as this is now optionally required by the image-transform module
no-issue
This ensures that running individual tests are not relying on other
tests having been run so they suceed, specifically the
regression/site/site_spec.js tests
- mock non existant module util was defined twice
- split it out properly from the rest of the utils, update all references
- this allows us to move this util out of the codebase along with other code, e.g. the image manipulation code
no issue
- Migrations within a minor have to be named with numbered prefixes like 01-, 02-, 03-.
- These two migrations were merged into master in the same time window which lead to having incorrect naming
- Moved zipFolder to a new package
- also exposing extract-zip from the new package
- new package has the API pre-promisified
- also uses @tryghost/extract-zip instead of extract-zip, which has bugfixes
- Show us how long it takes to start Ghost in each acceptance/regression test that uses this method
- Useful for debugging slow tests, and also Ghost boot time!
- Basic set of tests checks that our default behaviour works as expected
- Moved current acceptance tests to api-acceptance, and added this in frontend-acceptance
- This reduces nesting, and will help when we eventually separate the frontend out entirely
- Apps are marked as removed in 3.0, never officially launched and have been deprecated for at least 2 years.
- We've slowly removed bits that got in our way or were insecure over time meaning they mostly didn't work
- This cleans up the remainder of the logic
- The tables should be cleaned up in a future major
- Apps are marked as removed in 3.0, never officially launched and have been deprecated for at least 2 years.
- We've slowly removed bits that got in our way or were insecure over time meaning they mostly didn't work
- This cleans up the remainder of the logic
- The tables should be cleaned up in a future major
- The existing common.i18n library contained code for core and theme translations
- There is some shared logic and some theme-specific logic, and the theme-specific logic has dependencies we don't want in lib/common
- This refactor introduces an I18n base class that does all the main shared logic, with no dependencies on other parts of the codebase
- ThemeI18n then extends this logic, and replaces the functions it needs to handle differently and adds it's dependencies on config and settingsCache
- The class has several methods broken down into smaller pieces to make it easier to extend only the necessary parts
- The class also encapsulates all of its logic, without external functions or variables
- The function loadThemeTranslations becomes the 'init()' function overridden in themeI18n.
no issue
- prep for extraction of various Koenig repos
- html->mobiledoc doesn't really fit into the "renderer" naming as it's more of a converter than a renderer and doesn't follow the same pattern
refs #11464
- Combine reading + parsing of translation file into same step
- DRY reading / parsing logic
- Log an error when parsing fails and fall back as if the locale doesn't exist
closes https://github.com/TryGhost/Ghost/issues/10972
- adds `amp-youtube` to the allowed AMP components list
- adjusts `{{amp_components}}` output to include the `amp-youtube` script if any iframes with youtube urls are detected in the AMP content
Co-authored-by: Joseph Coffland <joseph@cauldrondevelopment.com>
no-issue
This adds two new endpoints, one at /ghost/.well-known/jwks.json for exposing
a public key, and one on the canary api /identities, which allows the
Owner user to fetch a JWT.
This token can then be used by external services to verify the domain
* Added ghost_{public,private}_key settings
This key can be used for generating tokens for communicating with
external services on behalf of Ghost
* Added .well-known directory to /ghost/.well-known
We add a jwks.json file to the .well-known directory which exposes a
public JWK which can be used to verify the signatures of JWT's created
by Ghost
This is added to the /ghost/ path so that it can live on the admin
domain, rather than the frontend. This is because most of its
uses/functions will be in relation to the admin domain.
* Improved settings model tests
This removes hardcoded positions in favour of testing that a particular
event wasn't emitted which is less brittle and more precise about what's
being tested
* Fixed parent app unit tests for well-known
This updates the parent app unit tests to check that the well-known
route is mounted. We all change proxyquire to use `noCallThru` which
ensures that the ubderlying modules are not required. This stops the
initialisation logic in ./well-known erroring in tests
https://github.com/thlorenz/proxyquire/issues/215
* Moved jwt signature to a separate 'token' propery
This structure corresponds to other resources and allows to exptend with
additional properties in future if needed
no issue
- The flag has not been used and can be removed, to make the `members_subscription_settings` JSON record in `settings` table easier to read.
- It used to indicate Stripe configuration being present. Currently that is checked by looking up if Stripe config's `public_token` and `secret_token` values are present (example - https://github.com/TryGhost/Ghost/blob/3.11.0/core/frontend/helpers/ghost_head.js#L54)
no issue
Email template was incorrectly setting up publication icon url in case of subdirectory setup, leading to missing publication logo from newsletter emails in such cases. This adds the fix to use correct absolute url for publication icons in all setups.
no issue
- trying to read a file without the correct permissions would cause a
500 error
- this commit handles the error code and returns an appropriate
response
refs https://github.com/TryGhost/Ghost/issues/11648
- Removes Stripe plan entries from settings that are not formatted correctly.
- Incorrect formatting was caused by a bug in 3.10.0 Admin-Client where it wasn't able to find complimentary plan. Related fix for this here - 9e7a6b801a
no issue
- When created_at value is not provided it should be treated as an empty one instead of trying to import empty string.
- This scenario happens when the column is defined in CSV but no values are present (default parsed value is empty string '')
no issue
- prevent oembed fetching from accessing IP addresses or localhost domains
- prevent oembed endpoint from passing through fetched responses as-is
- reject any fetched data that does not validate against the oembed spec
- strip any unknown properties from the oembed response before returning
Credits: Nick Mykhailyshyn
no-issue
Essentially only active users should have their permissions loaded, this
means that suspended or inactive users are stripped of all permissions
until their status is changed.
closes#10323
* Fixed usage of hasMany for user->session
* Refactored changePassword to async function
* Deleted all user sessions when password changed
* Tested for session retained after password changed
* Added the session to the frame
* Skipped the current session when changing password
no issue
- Made date formatting coherent with the one used in API and the exporter
- Using JSON.stringify() here because that's exactly how API is getting it's formattting done atm
no issue
- Multiple currencies for membe plans were supported under the hood but never had a clear interface to manage them. This change allows to reference currently used currency and it's symbol from the theme layer with following syntax: `{{@price.currency}}` and `{{@price.currency_symbol}}
refs #11304
- Previously the schema publisher logo attribute was incorrectly given the logo url
- schema.org and Google's docs show the logo needing it's own type and url attributes
- I added the correct @type and moved the metaData.site.logo to the new url attribute
- This change now clears the error in Google's Structured Data tester
- A future improvement would be to size the site logo to 60px in height per Google's recommendation
fixes#11636
- malformed URLs passed to oembed API would cause `got` or `metascraper`
to throw an error and this would result in a 500 error from Ghost
- this commit catches the errors and returns a reasonable response
no issue
- Sentry flagged up a redirect URL for the POST action of accessing a
private site which would throw a 500
- `decodeURIComponent` would throw an error if it was passed bad data
- this commit moves the `decodeURIComponent` inside the try-catch to
handle the error
no issue
- Adds 'GET /members/:id/signin_urls' endpoint to Admin API allowing to fetch login URL for member. This URL allows to log in as a member which is useful in situations when you need to impersonate a member (for example to debug some issue they are having)
- Added member_signin_urls permission with migrations. Only the "Owner" user can read "signin_urls" resource. Admin and other users will be denied access
refs 91984b54ca
- For request effieciency we should be using a minified file just like we did previously with `ghost-sdk.js`
- Modified 'max-age' caching header to 1 year for both minified and non-minified files as thay won't affect dev environment and should be beneficial for self-hosting instances that don't use minification
- Along the way corrected an extra 301 redirect because `/public/member.js` path wasn't using a bakslach in the end.
no issue
- This functionality allows member to update their billing information, like credit card information.
- Adds handler to update Stripe billing when element with `data-members-edit-billing` attribute is present on the page. Additional `data-members-success` and `data-members-cancel` attributes could be used to control the redirects on billing update success or failure. They work in the same fission as for 'members-plan' (https://ghost.org/docs/members/checkout-buttons/#redirects)
no issue
- teardown is an internal Mocha hook, and eslint would complain about it
being used outside a test
- our use of teardown is actually a custom function, so it's better to
rename the function across the board
no issue
The email data attached to a post when published with send email flag was not filtered on member access, and picked up the whole member list for email data. This resulted in incorrect data stored in emails table even in case of paid-members-only publish, and also incorrect count of "emails sent" being displayed on Admin.
NOTE: The actual emails being sent are still gated by member access, so no emails were sent to anyone without access, this only affected the associated email data and count. Also, the fix here will show correct email sent status for any future post, but will still show incorrect data for any already published posts as the email data in DB is already wrong and will probably need a migration
no issue
- After investigating effects of allowing editing email there were no significant blockers found, so there is no reason not to allow editing this field
no issue
- This field is usefult when importing from external sources.
- The date format should be compatible with one used internally by Ghost which is RFC 2822 compliant format
refs https://github.com/TryGhost/Team/issues/243
- uses `member.toJSON()` to add a computed `avatar_image` property
- if the member has an email address and gravatar is not disabled then we generate a gravatar url using the `?d=blank` parameter to return a transparent image if the member's email has no gravatar
no issue
- 3.6.0 contained incorrect references in the `schema.js` file for the `members_label` table that was added in that version. On MySQL knex created a foreign key constraint for that reference which stopped member labels from being createable
- this fixes the schema file and has a migration to drop and recreate the table. Knex handles removal and addition of foreign keys during table drop/create
no issue
- When importing through CSV we should remain the defaults of 'subscribed' fields (`true` at the moment), unless it is explicitly set to `false` or `FALSE` (the latter uppercase value often comes from scpredsheets)
no issue
- some errors weren't being reported because they were being passed to
Sentry before our middleware could populate the error information
- this commit inserts the Sentry middleware into these steps
no issue
- when `servePublicFile` middleware serves an image it resulted in a "Cannot set headers after they are sent to the client" error because `next()` was erroneously called for successful requests which then tripped the `prettyUrls` middleware which tries to perform a redirect
- only calling `next()` when an error is present allows errors to be picked up by later middleware but successful requests end in the `servePublicFile` middleware
no issue
* Updated sendEmailWithMagicLink syntax
* Updated label name selection from theme
* Updated migration version for labels
* Added labels to export/import of members
* Added member labels sanitization for case-insensitive duplicates
* Fixed tests
* Fixed label serialization bug on import
* Bumped @tryghost/members-api to 0.15.0
* Fixed lint
* Cleanup
no issue
- Allows for syntax like `{{#has visibility="paid"}}` to be used on Content API resources (posts, pages, etc.)|
- The need for this change cropped out from being able to distinguish paid/member-only/public posts in member-enabled themes.
no issue
We missed handling `undefined` values for fields during csv export for memebrs, which causes csv entries as `undefined` for fields that don't exist. It also added need for extra handling of `undefined` entries during csv import. This PR fixes the bug by properly handling empty/undefined values in export
no issue
- When new Ghost instance is initialized "Complimentary" plan doesn't have to wait for the rest of plans to be configured.
- Without configured plans the admin would still be able to assign "Complimentary" plan to members or import same kind of members.
- There is no error handling at the moment when plan initialization fails, that's why it was very confusing when all of the sudden it wasn't possible to create a member record
closes#11589
- `findOne` method in destroy method was usinng wrong options object (unlinke read method id comes from frame.options not frame.data) thus this was causing 404 errors
- The filename is returned to be able to fetch the backup on demand
- Wasn't able to limit exported tables as exporter doesn't support such functionality
no issue
- serving of our public asset images was broken
- we were reading the binary file in as a string so we could do url transforms, this meant data was lost/corrupted and browsers could not display the served data
- we were using the wrong mime-type for pngs which meant browsers were triggering downloads rather than displaying images (at least when accessed directly)
- updates uses of `servePublicFile` to have the correct png mimetype
- adjusts `servePublicFile` to treat any mime type starting with `image` as a binary file, passing the file directly through express using `res.sendFile` and skipping the in-memory content caching which is mostly only useful for text files with URL transforms
no issue
- When importing large batches of members we should not allow for unlimited amount of parallel requests created as this might lead to connection pool problems and reaching API rate limits (for example Stripe API is limited to 100 req/s)
no issue
- if a request was sent for an resized image URL that didn't contain a
file extension, the code would eventually end up throwing a 500
- this commit checks for this case and returns a 404
no issue
- New fields that are accepted through members CSV import endpoint are:
- `subscribed_to_emails` - corresponds to `subscribed` flag in API
- `stripe_customer_id` - links existing Stripe customer to created member
- `complimentary_plan` - flag controlling "Complimentary" plan subscription creation for imported member
- Noteworthy exception in field naming - `subscribed_to_emails` that corresponds to `subscribed` API flag present on members resources. It's a special case of CSV format, where users can be less technical it's more explicit to what the flag does (also the same naming is applied in the Admin UI)
- Failing to either link Stripe customer or assign "Complimentary" subscription to imported member behaves in a transaction-like manner - imported record is not created in the database. This is needed to be able to retry imports when it fails for reasons like connectivity failure with Stripe or Stripe miss-configuration.
- To avoid conflicts with linking same Stripe customer to multiple members there is a special handling for duplicate `stripe_customer_id` fields. Records with duplicates are removed from imported set.
no issue
- a couple of regressions tests would repeatedly fail on CI. They would
always follow tests that closed the Ghost server beforehand.
- this commit doesn't close the server after those tests have completed,
which is similar functionality to all other tests
- the actual cause is unknown at this point, but I suspect it's some
sort of race condition
no issue
- we would regularly see IO errors coming from SQLite, which caused
random regression tests to fail
- the default journal_mode is `delete`, but this is slow and can cause
issues when multiple tests try to remove the journal file
- `truncate` is faster and shouldn't cause these issues
This reverts commit 6e024331eb.
Temporarily reverting whilst we investigate an issue with Sentry and running Ghost via Ghost-CLI.
Ghost-CLI initiated boot was failing when Sentry was installed due to what appears to be `process.cwd()` returning `undefined` here https://github.com/TryGhost/Ignition/blob/master/lib/config/index.js#L26
no issue
- We need a way to simulate "premium" membership without any payment from members' side. For this new "Complimentary" plan is introduced
- Allows `comped` flag as an input only on `PUT /members/:id` endpoint which sets free subscriptions based on "complimentary" plan on the member
- Added `comped` flag to members endpoint responses
- Bumped members-api to 0.12.0. This version supports new set/cancel complimentary subscription methods
no issue
- This helper allows to format currencies that use decimal normalization. For example 19.35 USD is served as 1935 from the API which always needs to be divided by 100 to get a dollar ammount.
no issue
- the `hr` mobiledoc card does not specify an `absoluteToRelative` or `relativeToAbsolute` transformer function so falls back to the default transformer
- the default transformer function's arguments were not correct which meant that the UrlUtils object was replacing the card's typical empty-object payload
- the card's payload changing when saving mobiledoc was triggering the editor's unsaved changes warning because the API response no longer matched what was in the editor
no issue
- requests for resized images with a trailing slash would end up
throwing a EISDIR error because it got through to writing an
image buffer to a directory
- we want to cut this off early and disallow trailing slashes
refs https://github.com/TryGhost/Ghost/pull/11499
- Removed unused and confusin isPaymentConfigured because it was basing it's logic on old `isPaid` flag. Having it in the codebase was adding confusion.
- `isPaid` config flag still needs a proper cleanup with a migration etc.
- Added little post PR merge cleanup
closes#11463
- Ghost used to always load stripe.js into the frontend of all pages when memberships are enabled, even when Stripe isn't configured / memberships to a page are free. This changes Ghost's behaviour to only load stripe.js when both stripe API tokens are present & not empty (the quickest way to verify that Stripe is fully configured & operational on a blog).
- Needs a follow-up cleanup removing confusing/not functional `isPaymentConfigured` method from members service
no issue
- a request for a filename longer than those allowed by the filesystem produced a ENAMETOOLONG error, which would end up becoming a 500 error from Ghost
- this catches the error and returns a HTTP 400 Bad Request response
refs https://github.com/TryGhost/Members/pull/105
- As members module has become a core part it makes sense to follow the same principles as in all other controllers and use the model directly instead of calling external services.
- Bumped @tryghost/members-api to 0.11.1 . New stripe-specific methods used in controllers are available starting with this version
- Exposing these new methods is a little hacky because there are no relationships setup on members_* tables. Left notes for future improvements once relations are introduced.
- We don't allow for chaging member's emails at the moment. For this reason had to modify JSON schema a little. It doesn't support OO inheritence: "This shortcoming is perhaps one of the biggest surprises of the combining operations in JSON schema: it does not behave like inheritance in an object-oriented language. " (ref. https://json-schema.org/understanding-json-schema/reference/combining.html#allof)
refs c059e8e32e
- Reason why the refactor was needed can be found in refed commit
- The logic was extracted into members-api through passing models
directly as member-api module constructor parameters
- Bumped @tryghost/members-api to 0.11.0. Needed to work after the
refactor
refs https://github.com/TryGhost/Ghost/issues/10471
- Allow page resource endpoints to accept HTML source. This behavior is the same as the post's resource introduced with e9ecf70ff7372f395b8917340805148bc764e2ef
- The functionality was most likely missed when post split into posts & pages was happening.
- Added symmetric changes to API v2.
refs https://forum.ghost.org/t/plaintext-value-is-empty-using-the-api/10537
- The `plaintext`/`html` fields were empty because `visibility` attribute was not present in response body on output serialization stage. `visibility` field is always needed for content gating to work as expected
- Added `visibility` field in the input serialization layer as it wouldn't be possible to use content gating if added on model layer through `defaultColumnsToFetch`
- Added test cases covering a bug
no issue
- There was a lack of any kind of tests checking if content gating
behaves as it should. These changes create a base to expand upon when
more changes are introduced into content gating mechanism
- One thing that would be great to add in the future is imitation of
member authentication to test the content is visible for authenticated
paying/non-paying members
- Added 'members only' tests
- Added 'paid' post test case
- Added plaintext gating test case
no issue
- We don't check for specifics of the error thrown in the other heper tests, don't see a reason to do so here. It's important to see the error was thrown at all in this case
no issue
Since we added `email_subject` to `posts_meta` table in `3.1`, the migration tries to add `email_subject` column from post table, which does not exist and thus tries adding `undefined` value for column. Since sqlite expects default values while inserting new columns, this breaks any migration directly from `1.x`/`2.x` to 3.x.
The fix adds a default `null` value for any post_schema entry which doesn't has a value.
refs https://github.com/TryGhost/Ghost/issues/11461
- The email feature was introduced in API v3 and is not back compatible with API v2. These fields should not appear in any v2 responses.
- Added regression tests for API v2 so that cases like this are spotted
easier in the future.
refs https://github.com/TryGhost/Ghost/pull/11462
Allows `comment_id` and `uuid` to be passed in post `add`/`edit` API calls instead of failing requests with validation error, though both properties are stripped out in serializer as we don't allow editing them.
no issue
- The helper allows generating HTML needed to cancel or continue the member's subscription depending on subscription state.
- Added public members endpoint to allow updating subscription's `cancel_at_period_end` attribute available at: `PUT /api/canary/members/subscriptions/:id/`
- Added client-side hook to allow calling subscription cancellation. Allows to create elements with `data-members-cancel-subscription` / `data-members-continue-subscription` attributes which would call subscription update.
- Updated schema and added migration for `current_period_end` column
- As discussed we only add a single column to subscriptions table to avoid preoptimizing for future cases
- Added {{cancel_link}} helper
- Added error handling for {{cancel_link}} when members are disabled
- Added test coverage for {{cancel_link}} helper
- Bumped @tryghost/members-api version to 0.10.2. Needed to use `updateSubscription` middleware
- Bumped gscan to 3.2.0. Needed to recognize new {{cancel_link}} helper
no issue
- This includes the interface change for members-api constructor - now accepts the member's model instead of proxy methods. These methods have been moved ton @tryghost/members-api in favor of using the model directly (ref: https://github.com/TryGhost/Members/pull/105)
- Moved error handling from the service layer to controller
- Bumped @tryghost/member-api package to 0.10.0
no issue
- This test was checking for a very edge casy scenario (blog timezone change when scheduled date for a post changes at the same time). It's been hard to keep it maintaned so had to go.
no-issue
Our function for determining cors options created a new instance of URL
without wrapping it in a try/catch which meant any failures to parse the
URL bubbled down as a 500 error.
500 errors are commonly used for alerting at the infrastructure level,
and this error is definitely one caused by a badly configured client, so
we wrap the construction and crap out with a Bad Request Error (HTTP
400) if it fails.
no-issue
This name `login` was misleading as this middleware didn't login
members, that was handled by the `authentication` middleware,
specifically `exchangeTokenForSession`
no issue
- Secondary navigation means most nav concepts are supported, e.g. header & footer, or left & right
- The UI is added separately, this PR adds supporting concepts:
- make sure the default value is an empty array
- add support in the API (v3 only)
- add handling in the navigation helper
no issue.
- "[Test]" being appended (at the end of) the test email subject made it hard to scan for test emails. This fixes it by prepending "[Test]" to the subject.
refs https://github.com/TryGhost/Ghost/issues/10062
- When content gating is in place a lot of times both `html` and `custom_excerpt` fields on posts/pages are empty and the output of `{{excerpt}}` helper is also empty. We do return an `excerpt` property as a part of post resource which can serve as a safe fallback for when the above fields are not filled. It massively improves the experience of using the helper with gated content
- Refactored nested ternaries to be more readable
- Added fallback to excerpt property when HTML is hidden from members
- Removed note about the review of excerpt helper
- Added test case for 'excerpt' property
Adds transaction support to `fetchPage` method. This is needed to be able to count members during the post publish transaction.
This is the next iteration over initial quick-fix: 90905b0212
* Added transaction support to pagination plugin
- This support is needed to be able to use `fetchPage` method in transactional context (example usecase was counting members when publishing post for emails)
* Passed transaction related options during email creation
- Without this SQLite would hang in a transaction and eventually timeout
* Updated parameter name for consistency
no issue
We changed `reschedule` event to trigger adapter's `unschedule` and `schedule` methods since we now generate separate tokens(urls) for consistency as two different url(token) is needed to complete the reschedule functionality.
no issue
The default scheduling generates a known, independent URL for publishing a resource. In case of resource being rescheduled or unscheduled, the adapter expects the the same URL to remove/update existing jobs. The URL includes a JWT token for API auth which is calculated from post model and appended to URL.
There was a bug in token generation which meant If we go to update or delete the job i.e. unschedule a post then a new token is used which means the existing scheduled job cannot be removed. This PR:
- removes issued at (`iat`) timestamp from token generation which lead to a different token being generated for same payload
- Fixes timestamp being used for URL calculation from resource model
no issue
- the schedules controller wraps the post creation in a transaction
- we need to pass that transaction through to all other queries, especially on sqlite where a non-transaction query inside a transaction will lock up because there's only 1 connection available
- updates our model method calls to pass through the transaction options
- switches the members service `list()` call to a direct model `findAll()` call to avoid going through our pagination plugin because the raw knex query does not respect the transacting option
no issue
- When having following routes.yaml configuation and theme runing API v3:
routes:
/:
data: page.home
template: home
- There was an internall error in meta layer: `Cannot read property 'website' of undefined` which was caused by not being able to read primary_author on a fetched page
- We need to include authors and tags for pages, the same way we do for posts to prevent this error (as they should have identical properties from meta layer perspective)
no issue
- additional migration for the column added since the last 3.1 beta release to allow beta upgrades without rollbacks
- will be a no-op for upgrades from 3.0 as it's covered by `3.1/05-add-emails-table.js`
We want to allow admin users to trigger a retry of failed emails without having to go through the unpublish/republish dance.
- fixed resource identifier in email permissions migration so email permissions are added correctly
- added new email permissions migration so that beta releases can be upgraded without rollback (will be a no-op for any non-beta upgrades)
- added `/emails/:id/retry/` canary Admin API endpoint
- follows same URL pattern as theme activation
- only triggers mega service retry endpoint if the email has a `'failed'` status
no issue
- In order to keep site/app.js module tidy and less coupled with members module we need to extract some of the functionality where it belongs conceptually
- Added "members enabled check" middleware to stripe webhook endpoint
- Reshuffled members middleware so that siteApp is in control of mounting points. This is meant to be a more explicit way to see which endpoints are being handled by members middleware
- Extracted member-specific public file middleware
- Unified use of `labs.member` alias method. Done for code style consistency
- Added basic members' test suite. This is a base we could work from when more modifications are needed
- Removed route handler for unexisting members file "members-theme-bindings.js". Calling this route otherwise causes a 500. Looks like a leftover from 49672a1e4d
no issue
- a 401 is received from Mailgun when invalid credentials are used but the default error message of "Forbidden" is not particularly useful
- intercepts "Forbidden" and swaps it for "Invalid Mailgun credentials" to be more user-friendly
no issue
- When whole email batch fails we want to allow retrying sending a batch when post is republished
- Refactored naming for email event handling in mega
no issue
- Increased default mailgun retry limit to 5
- Handling retry logic closer to SDK layer gives less future manual handling
- Allowed failing request to be passed through to the caller
- To be able to handle failed requests more gracefully in the future we need all available error information to be given to the caller
- The previous method with `Promise.all` would have rejected a whole batch without providing details on each specific batch.
- Limited data returned with a failed message to batch values
- Added better error handling on mega layer
- Added new column to store failed batch info
- Added reference to mailgan error docs
- Refactored batch emailer to respond with instances of an object
- It's hard to reason about the response type of bulk mailer when multiple object types can be returned
- This gives more clarity and ability to check with `instanceof` check
no issue
- adds new router to the frontend for handling unsubscribe
- default template lives in `core/server/frontend/views/unsubscribe.hbs`
- `{{error}}` is present and contains the error message when unsubscribe fails
- `{{member}}` is present and contains the member email
- updated unsubscribe url to match the new format
no issue
- having a `send_email_when_published` property on the Post resource that only has an effect at certain times was confusing and was causing issues with clients that needed to know details of how that toggle worked
- makes `post.send_email_when_published` a fully read-only property in the API
- adds support for `?send_email_when_published=true` query param that can be passed in POST/PUT requests to the posts endpoint when scheduling or publishing a post - this is the only way to set `post.send_email_when_published` to `true`
- adds handling to ensure that `post.send_email_when_published` is always reset to `false` when reverting a post back to a draft _unless_ an email has already been sent