refs https://github.com/TryGhost/Team/issues/1259
These errors are thrown by nodemailer and can occur when an invalid
email address is used. Without special handling these cause a 500 error.
refs https://github.com/TryGhost/Team/issues/789
We are still having issues with duplicate subscriptions being inserted,
despite running our code in transactions. For now we will catch these
errors and response ot Stripe with a 409 so that it'll retry later - and
it stops us from throwing 500's
closes https://github.com/TryGhost/Team/issues/1238
- previously returned 500 errors when a subscription had multiple prices due to external tampering on Stripe directly
- instead now returns 400 Bad Request error when subscriptions don't have right number of prices
refs https://github.com/TryGhost/Team/issues/1067
This decouples the contents/type of email from the webhooks service,
allowing us to easily make changes to the type of email sent, without
having to make changes to the webhooks service.
refs https://github.com/TryGhost/Team/issues/1243
It's possible to get into strange states where a subscription in Ghost
doesn't have an associated Price. This then has knock on effects because
we're dealing with data in an undefined state. Rather than add guards
against this throughout the entire stack, we stop returning it from the
BREAD API. It might be worth considering removing these subscriptions
from the response of the repository, but for now this is the most
minimal change that fixes the problem.
refs https://github.com/TryGhost/Team/issues/1092
refs https://github.com/TryGhost/Team/issues/1135
This was missed in the initial due to the issue tracking the task being
superceded, and the task not being copied across to the superceding
issue.
A new method to remove coupons has been added, as opposed to updating
the existing change subscription price method, because the removal of a
coupon is not the concern of an auxillary stripe service, but a busines
concern that should be explicit in the members-api codebase.
refs https://github.com/TryGhost/Team/issues/1067
The auto-login behaviour obliterates the concept of a success URL,
because the Member is redirected in a logged in state, to the welcome
URL - rather than a logged out state to the success URL.
In order to not disrupt existing flows, we disable auto login if a
success URL is provided.
refs https://github.com/TryGhost/Team/issues/1067
This is the MVP for auto-login of Members, it does not support custom
redirects, and will always just redirect to the same place that the
signin & signup links do. Behind a feature flag whilst we iron out the
functionality.
refs https://github.com/TryGhost/Team/issues/887
Our invoice webhook handling code assumed that every invoice would be
for a subscription, but that is not the case. There are valid use-cases
of using the same Stripe account in order to sell items with a one-off
purchase. Here we update the handling to ignore all invoices which are
not for subscriptions.
no-issue
When adding a new member, we allow an email to be sent, and the type of
email to be chosen. This choice was being overriden by our signup email
logic - here we allow the BREAD API to have full control over which
email is sent.
refs https://github.com/TryGhost/Team/issues/885
This webhook isn't used and can cause issues when Checkout Sessions are
completed but with a failed payment. Removing it will remove those
errors.
refs https://github.com/TryGhost/Team/issues/1135
We use the OffersAPI to fetch Offers, so that we can be using the same
format for Offers in all of our APIs.
We will not attach the Offer to the Subscription if either the Tier or
the Cadence do not match. This is because the Offer would no longer
apply to this Subscription.
We do however retain the data, so that a Member can still be filtered on
the Offers which they've redeemed.
refs https://github.com/TryGhost/Team/issues/1166
By using the PaymentsService to fetch coupon information - we ensure
that the coupons are created if they're missing. Like in the case of a
Stripe disconnect/connect cycle.
no-issue
Without forcing linkSubscription to run inside a transaction - it's
possible to have race conditions where it is called twice, and attempt
to insert duplicate rows into the database.
refs https://github.com/TryGhost/Team/issues/1132
We have to include the Offer on the metadata for the Stripe Checkout -
as Offers with a duration of 'once' will not always be present on the
Subscription after fetching it.
Once we receive the Stripe Checkout webhook we emit an event for
subscription created - the reason we use an event is because this logic
should eventually live in a Payments/Stripe module - and we'd want to
decouple it from the Members module.
The Members module is in charge of writing Offer Redemptions - rather
than the Offers module - because Offer Redemptions are "owned" by a
Member - and merely reference and Offer. Eventually Offer Redemptions
could be replaced by Subscriptions.
refs https://github.com/TryGhost/Team/issues/1156
Because we were only attempting to add the product to the members if the
subscription was new AND active - we would not add it for incomplete
subscriptions transitioning to active.
Instead we always attempt to add the product to a member for an active
subscription - it doesn't matter if it's a new one. We later have logic
to filter out duplicate products if the member already has access to the
product.
refs https://github.com/TryGhost/Members/commit/5172e40646
When we updated to use the OffersAPI instead of OfferRepository this was
missed, and we were passing blank coupon to Stripe Checkout. This should
eventually be replaced with a call like `getCoupon(offerId)` from a
payments service.
refs https://github.com/TryGhost/Team/issues/1133
An archived Offer is intended to be disabled from a redemption point of
view. This ensures that we do not allow Stripe Checkout Sessions to be
created for them.
no-issue
The OfferRepository deals with domain objects in the Offers module, and
as such is not suitable for use with "external" services. This update
means that MembersAPI can deal with POJO DTOs so that there is not a
dependency on the internals of the Offers module. Just on the contract
it holds with the outside world.
refs https://github.com/TryGhost/Team/issues/1090
Instead of the hardcoded 1-day version for Offers, we can now talk
directly to the Offers repository and use the real values for Stripe
Checkout.
refs https://github.com/TryGhost/Team/issues/1083
The Offers service is going to need access to the StripeAPIService too,
so we must pull its initialisation out of this module up to the Ghost
application layer, which will allow us to pass a reference of the
StripeAPIService to wherever needs it.
refs https://github.com/TryGhost/Team/issues/1090
This 1-day version of Offers allows us to test the full flow of the
Offers feature without having to implement all of it. The focus here is
that we can pass an Offer ID when creating a Stripe Checkout session and
have it apply. Here we use hardcoded Stripe Coupons as we haven't yet
got persistence implemented for Offers & their related Stripe Coupons
no-issue
Without a return after ending the response, the code will continue to
attempt to send emails and then send another response which results in
an uncaught error.
refs https://github.com/TryGhost/Ghost/security/advisories/GHSA-65p7-pjj8-ggmr
The email address change flow was built on top of the unauthenticated
signin/signup flow. This meant that ownership of the email being changed
wasn't verified and allowed a malicious actore to change the email
address of arbitrary accounts to an email address which they controlled.
We remove the ability to change email addresses from the signin/signup
flow and instead create a dedicated, authenticated flow for changing
email address.
refs https://github.com/TryGhost/Team/issues/1054
We need to instantiate the MemberAnalyticsService so that we can start
listening to events and storing them, this is the minium glue code
required to get us going.
refs https://github.com/TryGhost/Team/issues/1057
This method will validate a token, and then return the member associated
with it. Rather than exposing token validation and coupling consumers to
the structure of the token response data.
refs https://github.com/TryGhost/Team/issues/873
This ensures that all requests to the API will include the mock
subscriptions for comped members. Allowing the Admin to correctly show
the subscription information after adding and editing members. As well
as having the correct information when navigating from the list of
members to an individual member.
no-issue
Previously we would not create an instance of the StripeAPIService if
Stripe was not configured, but that is not the case any more, instead we
have a configured flag on the service. The webhook route handler was not
updated to use this flag and so would attempt to handle webhooks without
having any of the required data. This would result in an uncaught error.
refs https://github.com/TryGhost/Team/issues/1006
When disconnecting from Stripe, we currently do not remove the webhooks,
this will result in the webhooks from Stripe failing, and tending toward
a 100% error rate, which will ultimately result in emails from Stripe
about the failing webhook.
In order to stop all of that from happening, we should make sure that we
actively remove the webhook from Stripe when disconnecting.
refs https://github.com/TryGhost/Team/issues/1006
As part of the work to handle cleaning up webhooks when we disconnect
from Stripe, I'm moving the logic to clear out the Stripe related data
from the database into a disconnectStripe method. This then allows us to
start handling the cleanup of webhooks via the Stripe API.
refs https://github.com/TryGhost/Team/issues/995
Since we reintroduced the comped status, we did not update the
subscription handling to correctly set members to a status of comped
when they were on a 'Complimentary' plan.
no-issue
Since updating the product repository to force transactions, the options
parameter was used in every call, meaning it wasn't optional any more,
which broke usage. This updates the parameter to have a default so that
existing usage still works.