no-issue
Previously we would blindly put subscriptions into the database when we
received a webhook, which could result in orphaned rows that were not
linked to a customer (and by extension a member)
This updates the logic so that we will only add subscriptions if we have
a record of their customer.
Customers are only added during a checkout.session.completed webhook, at
which point a member is guarunteed, but for formailty and safety against
changes in the flow, the logic has been applied to inserting customers
too.
refs https://github.com/TryGhost/Ghost/issues/11557
If a subscription failed to delete, we would error and bailout of the
process, this updates it to log the error so that site owners have a
record of the error in the logs, but also to continue through the rest
of the subscriptions.
no-issue
Destroy is terminology we usually use for the model layer and was a
little confusing without context, this method is used in one place so
it's a low effort cleanup with minimal repercussions
refs https://github.com/TryGhost/Team/issues/342
- Send magic link middleware was not using custom status code from error and sending 500
- Updates error code to be picked from err object if present, or fallback to 500 as before otherwise
refs https://github.com/TryGhost/Ghost/issues/12074
Some sites may have had duplicate webhooks created due to a race
condition. This updates the members-api to cleanup _all_ webhooks before
starting, allowing it to create webhooks on a fresh slate, and removing
possible causes of 401 errors due to incorrect webhook secrets.
refs https://github.com/TryGhost/Ghost/issues/12065
This protects us against multiple instances of the members-api being
started simultaneously and race conditions where inbetween the initial
"GET" of a plan which returns empty, and the "POST" of a plan to create
it, another instance has already created it.
no-issue
This fixes a problem when subscribing to a Plan (Price) with a default
trial period. We also add logging to add a little more information about
which flow we're entering.
Subscriptions that are started with a trial have a `setup_intent`
present on the Checkout Session object, which was incorrectly causing us
to determine that we are in a "setup" flow and attempt to update a
customers card details.
We now use the `mode` property of the Checkout Session to determine
whether we are handling a new Subscription, or if we are in a "setup"
flow and should update the Customer's card details.
no-issue
This fixes a problem when subscribing to a Plan (Price) with a default
trial period. We also add logging to add a little more information about
which flow we're entering.
Subscriptions that are started with a trial have a `setup_intent`
present on the Checkout Session object, which was incorrectly causing us
to determine that we are in a "setup" flow and attempt to update a
customers card details.
We now use the `mode` property of the Checkout Session to determine
whether we are handling a new Subscription, or if we are in a "setup"
flow and should update the Customer's card details.
refs https://github.com/TryGhost/Ghost/issues/12061
Due to a bug in Ghost webhooks are now created with a trailing "/" which
meant that the previous webhooks to that (without a slash) was never
removed.
This results in users receiving emails from stripe about failed webhook
delivery, which is not good at all.
This fix lists out the webhooks and finds (if present) the webhook which
matches the current URL, minus the trailing slash. If found it will then
attempt to delete that webhook thus stopping the emails from Stripe.
I've added a note to remove this code as it should only ever need to run
once, and can be removed for the Ghost release after these changes.
no-issue
* Refactored model dependencies
This groups all of the model depenencies into a single models object,
and renames the models with more concise identifiers
* Fixed spacing
* Added webhook support to metadata
* Refactored stripe configure to have better logging
* Refactored webhook creation to reuse existing webhook
* Installed @types/stripe
no issue
- The extra payload added to magic link token included `name`, `labels` and `oldEmail`
- Refactor in commit [here](bf63ffe424 (diff-9f9ef757543bb9a90baba0d3bea76a83L157-R169)) changed the `body` variable assignment causing the payload objection creation to not include the extra data from request body
- Updates `body` to `req.body` to use correct data from request
refs 5c46786ebc
- This is continuation of work removing csv-parser as main CSV handling library with more suitable papaparse library
- Referenced commit introduced papaparse as a library to serialize JSON to CSV, this changeset takes it a step further and replaces CSV to JSON seriazliation logic
no issue
- When processing CSV files `parse` function now allows for the client to specify "mapping" parameter in format of a hash as follows:
{ destination_property_name: 'source_column_name'}
e.g.:
{
name: 'weird_name_column',
email: 'email_column'
}
- It is done so to allow for the end user to provide exact mapping of the fields to be transformed into JSON.
no issue
- This fixes a problem where files are skiped form the @tryghost/members-csv package
- Also this follows the file structure convention with other packages
refs 8185b42d9e5fd9e9051f08ce3395a648ec02f3a4
- Allows to move files and keep the history in one go.
- 'csv-parser' will be upgraded to 'papaparse' lib in a new package
- 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 method is needed to be able to validate if customer exist in configured Stripe account before attempting to link one with local member.
refs https://github.com/TryGhost/members.js/issues/38
- In case of incomplete Stripe setup like Account name, checkout session creation fails and throws error, which was not being handled and 200 returned after long timeout
- This change catches the error and returns correct status along with message for clients to handle it downstream
closes https://github.com/TryGhost/Members/issues/148
- geolocation was not being fetched/stored for paid member signup
- magic link was being sent after Stripe webhook but we don't have an IP at that stage
- it only worked when a magic link was requested by the browser
- moved the geolocation fetch/update to `members-ssr`
- kept the ip geolookup and storage inside `members-api` but exposed it as a method so consumers are able to choose when it's performed
- used the new api method in `members-ssr` when exchanging a token from the session as that is always driven by browser requests so we know we have an IP and it's likely the correct one (reliant on consumers having "trust proxy" config correct)
- stopped storing IP addresses in the token payload (keeps links shorter)
refs https://github.com/TryGhost/members.js/issues/30
- Updates `sendMagicLink` middleware to allow adding old email address to payload. Checks for if new email address already exists in db before creating magic link, throws error in case of duplicate email.
- Updates magic link parsing for data to check if the intention is to update email address and update member's email to new email address in case its allowed.
- Return session data from magic link using the new email address
no-issue
Without this flag the checkout session will ignore any default trial periods
attached to the plan. Now we are able to give basic support for trials, by
attaching a trial period in Stripe Dashboard
no issue
- Makes passing `name` and `note` field in member update data as optional instead of making them undefined
- Allows email to be updated
- Adds stripe subscriptions list to updated member's response data to make update consistent with get method
refs TryGhost/members.js#29
- Uses the metadata option in stripe checkout flow to add member's name on creation via anonymous checkout flow
- Allows clients like memebrs.js to pass member's info like name from checkout signup flow
refs TryGhost/members.js#29
- Allows passing metadata to checkout session API
- Metadata is passed to stripe's checkout session on creation and read back from webhook event
- Allows clients like members.js to pass custom info like member name to Stripe flow
no issue
- Current update stripe subscription API calls only allowed cancelling a plan
- This change adds option to pass plan's nickname as `planName` in request to update subscription to new plan
- Checks if plan name is valid and updates stripe subscription to new plan at default prorate behavior
refs https://github.com/TryGhost/members.js/issues/10
- Allows passing an additional `customerEmail` value to our checkout creation API
- This value is used to pass `customer_email` option to stripe's checkout session - https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-customer_email.
The `customer_email` allows pre-filling the customer's email field in case of an anonymous checkout as customer doesn't exist already, and also ensures the stripe subscription is created with same email address as given by user during signup flow.
no issue
We were using incorrect method for logging in geolocation warning - `this.logging.warn(err)` - as `this.logging` doesn't exist in this file. Updated to use correct logging method.
no issue
- Adding these properties allows specifying which currency is currently used on member's plan.
- Supported currencies list: USD, AUD, CAD, GBP, EUR
- They were chosen based on the most used/requested currencies within Ghost
- With adding multiple available currencies that can be setup also had to add handling of Stripes limitation of having single currency per paying customer
requires f38d490886
- adds `lib/geolocation.js` with `getGeolocationFromIP()` function which uses https://geojs.io to lookup geolocation data from an IPv4 or IPv6 address
- updates `create/updateMember()` functions to work with a `geolocation` property in the passed in object
- if `geolocation` is `undefined` when updating a member do not reset any existing property
- updates `sendMagicLink` middleware to extract the IP address from the request and stores it as part of the token payload
- updates `getMemberDataFromMagicLinkToken()` method to extract the IP address from the token payload and perform a geolocation lookup if we have an IP address and a matching member does not already have geolocation data
This reverts commit 5f0d2168f3.
After discussing the best approach to multipe currency problem would be
to allow creating multiple "Complimentary" plans. All security related
checks should stay strictly based on name and would not cause issues.
refs https://github.com/TryGhost/Ghost-Admin/pull/1430
- When the client creates a complimentary plan with other currency than USD we should not allow for it to avoid creating a mess in the Stripe plans
refs https://github.com/TryGhost/Ghost/pull/11571
- Allows updating members billing information through Stripe's setup intent (stripe.com/docs/payments/checkout/subscriptions/updating#set)
- Accepts 2 new parameter to handle redirects specific to billing update.
no issue
- On model layer in Ghost empty string is always converted to `null` for not nullable fields, which wasn't letting the value through to the database
- Current solution is a stopgap to fix imports of cyclic plans without nicknames. Ideally nickname field should become nullable in the future so this logic can be simplified
no issue
- This solves a problem when connected Stripe plan doesn't have plan `nickname` filled out (possible with older versions of Stripe API)
- Defaulting to empty string instead of creating a migration because SQLite doesn't support `ALTER ... MODIFY` syntax and thus knex can't altter the table that easy
- "Marks the column as an alter / modify, instead of the default add. Note: This only works in .alterTable() and is not supported by SQlite or Amazon Redshift. Alter is not done incrementally over older column type so if you like to add notNull and keep the old default value, the alter statement must contain both .notNull().defaultTo(1).alter(). If one just tries to add .notNull().alter() the old default value will be dropped." (ref. https://knexjs.org/#Chainable)
refs https://github.com/TryGhost/Ghost/pull/11537
- Adds ability to assign and cancel "complimentary" type of subscriptions to the member
- The functionality is needed to be able to provide free premium plans for members (e.g. family members, trials, gifts)
- When member already has an active paid subscription and complimentary one is applied the old one is upgraded. Proration is not given
- When deleting a subscription we need to update localy stored records right away to be albe to reflect the change in the UI. This behavior will also be in line with how subscriptions updates/creates are handled
- Blocked any client update for complimentary subscription. We should prevent non authenticated clients from upgrading/subscribing themselves to "complimentary" plan.
no issue
- `customers` property contains an array of customer for which 'for..of' syntax is more appropriate
- Bug was causing creation of multiple customers in Stripe when new checkout session was initiated for existing customer
- Discussed in https://github.com/TryGhost/Members/pull/90/files#r368889289
refs https://github.com/TryGhost/Members/pull/105
- It's a follow up to a series of refactorings in the module mostly discussed in refed PR
- The sendEmailWithMagicLink and destroyStripeSubscriptions were exposed through members API so that Ghost could call it from the controller level
refs #https://github.com/TryGhost/Ghost/pull/11434
- Added method to allow updating single subscription. Only `cancel_at_period_end` field can be updated.
- Middleware is needed to allow Ghost Core to cancel/uncancel member's subscription.
- Relies on the request containing identity information to be able to verify if subscription belongs to the user
- When member could not be identified by the identity information present in the request we should throw instead of continuing processing
- Handling and messaging inspired by https://github.com/TryGhost/Ghost/blob/3.1.1/core/server/services/mega/mega.js#L132
- When the user initiates subscription cancellation we can safely mark the subscription as canceled so that it's not shown in the interface on subsequent request. Otherwise, we end up in a situation where we still return the subscription in the period until Stripe triggers the webhook.
- Added boolean coercion for cancel_at_period_end parameter. If anything but boolean is passed to Stripe API it throws an error. Coercing the value on our side is a gives a better dev experience
no-issue
When using localhost urls the call to `create` will error and end in teh
catch block - so we need to use the environment variable there, too.
Introduced in 0149dd8f