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
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
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
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
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.
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
- 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/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
* 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
- 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)
- 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>
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
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
- 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
- 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
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
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 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.
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
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
- 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
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
}
}
* 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
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
- 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
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
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.
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
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
- 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
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
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
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
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 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.
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
- 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
- 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