diff --git a/server/cmd/museum/main.go b/server/cmd/museum/main.go index a4622e1b70..4ab0e58501 100644 --- a/server/cmd/museum/main.go +++ b/server/cmd/museum/main.go @@ -203,7 +203,7 @@ func main() { plans := billing.GetPlans() defaultPlan := billing.GetDefaultPlans(plans) stripeClients := billing.GetStripeClients() - commonBillController := commonbilling.NewController(storagBonusRepo, userRepo, usageRepo) + commonBillController := commonbilling.NewController(emailNotificationCtrl, storagBonusRepo, userRepo, usageRepo, billingRepo) appStoreController := controller.NewAppStoreController(defaultPlan, billingRepo, fileRepo, userRepo, commonBillController) remoteStoreController := &remoteStoreCtrl.Controller{Repo: remoteStoreRepository} diff --git a/server/mail-templates/account_deleted_active_sub.html b/server/mail-templates/account_deleted_active_sub.html index 1d33aebc10..dd6a82bda5 100644 --- a/server/mail-templates/account_deleted_active_sub.html +++ b/server/mail-templates/account_deleted_active_sub.html @@ -101,7 +101,7 @@ font-size: 16px; " >

Hey,

-

As requested by you, we've deleted your ente account and scheduled your +

As requested by you, we've deleted your Ente account and scheduled your uploaded data for deletion. If you have an App Store subscription for Ente, please remember to cancel it too.

diff --git a/server/mail-templates/subscription_cancelled.html b/server/mail-templates/subscription_cancelled.html new file mode 100644 index 0000000000..b242875332 --- /dev/null +++ b/server/mail-templates/subscription_cancelled.html @@ -0,0 +1,147 @@ + + + + + + + +
 
+
+

Hi there,

+ +

Vishnu here, CEO of Ente.

+ +

Thank you for giving Ente a shot, and apologies for not meeting your expectations.

+ +

This is my personal email address. Please let me know what we could have done better, we'd be grateful for feedback!

+ +

Best, +
+ Vishnu +
+ Founder & CEO at Ente +

+
+
+ + + diff --git a/server/mail-templates/subscription_ended.html b/server/mail-templates/subscription_ended.html index 8f658bbae1..9ea7938933 100644 --- a/server/mail-templates/subscription_ended.html +++ b/server/mail-templates/subscription_ended.html @@ -113,7 +113,7 @@

Your subscription to Ente Photos has ended. Thank you for trying us out!

- If you still have data stored in ente, we encourage you to follow the steps outlined here to export your data: help.ente.io/photos/migration/export. + If you still have data stored in Ente, we encourage you to follow the steps outlined here to export your data: help.ente.io/photos/migration/export.

If there's anything we could have done better, please let us know by diff --git a/server/pkg/controller/appstore.go b/server/pkg/controller/appstore.go index 428ae5319c..6325aa2843 100644 --- a/server/pkg/controller/appstore.go +++ b/server/pkg/controller/appstore.go @@ -3,11 +3,12 @@ package controller import ( "context" "fmt" - "github.com/ente-io/museum/pkg/controller/commonbilling" - "github.com/prometheus/common/log" "strconv" "strings" + "github.com/ente-io/museum/pkg/controller/commonbilling" + "github.com/prometheus/common/log" + "github.com/ente-io/stacktrace" "github.com/gin-contrib/requestid" "github.com/gin-gonic/gin" @@ -124,7 +125,7 @@ func (c *AppStoreController) HandleNotification(ctx *gin.Context, notification a return stacktrace.Propagate(err, "") } } else if notification.NotificationType == appstore.NotificationTypeCancel || notification.NotificationType == appstore.NotificationTypeDidRevoke { - err := c.BillingRepo.UpdateSubscriptionCancellationStatus(subscription.UserID, true) + err := c.CommonBillCtrl.OnSubscriptionCancelled(subscription.UserID) if err != nil { return stacktrace.Propagate(err, "") } diff --git a/server/pkg/controller/commonbilling/controller.go b/server/pkg/controller/commonbilling/controller.go index 8059d83a13..0e816bcf26 100644 --- a/server/pkg/controller/commonbilling/controller.go +++ b/server/pkg/controller/commonbilling/controller.go @@ -2,6 +2,8 @@ package commonbilling import ( "context" + + "github.com/ente-io/museum/pkg/controller/email" "github.com/ente-io/museum/pkg/repo" "github.com/ente-io/museum/pkg/repo/storagebonus" "github.com/ente-io/stacktrace" @@ -9,20 +11,26 @@ import ( ) type Controller struct { - StorageBonusRepo *storagebonus.Repository - UserRepo *repo.UserRepository - UsageRepo *repo.UsageRepository + EmailNotificationController *email.EmailNotificationController + StorageBonusRepo *storagebonus.Repository + UserRepo *repo.UserRepository + UsageRepo *repo.UsageRepository + BillingRepo *repo.BillingRepository } func NewController( + emailNotificationController *email.EmailNotificationController, storageBonusRepo *storagebonus.Repository, userRepo *repo.UserRepository, usageRepo *repo.UsageRepository, + billingRepo *repo.BillingRepository, ) *Controller { return &Controller{ - StorageBonusRepo: storageBonusRepo, - UserRepo: userRepo, - UsageRepo: usageRepo, + EmailNotificationController: emailNotificationController, + StorageBonusRepo: storageBonusRepo, + UserRepo: userRepo, + UsageRepo: usageRepo, + BillingRepo: billingRepo, } } @@ -63,3 +71,12 @@ func (c *Controller) CanDowngradeToGivenStorage(newStorage int64, userID int64) } return true, nil } + +func (c *Controller) OnSubscriptionCancelled(userID int64) error { + err := c.BillingRepo.UpdateSubscriptionCancellationStatus(userID, true) + if err != nil { + return stacktrace.Propagate(err, "") + } + go c.EmailNotificationController.OnSubscriptionCancelled(userID) + return nil +} diff --git a/server/pkg/controller/email/email_notification.go b/server/pkg/controller/email/email_notification.go index 56bc91f013..6f4048d603 100644 --- a/server/pkg/controller/email/email_notification.go +++ b/server/pkg/controller/email/email_notification.go @@ -24,6 +24,8 @@ const ( FilesCollectedSubject = "You've got photos!" SubscriptionUpgradedTemplate = "subscription_upgraded.html" SubscriptionUpgradedSubject = "Thank you for choosing Ente!" + SubscriptionCancelledSubject = "Good bye (?) from Ente" + SubscriptionCancelledTemplate = "subscription_cancelled.html" FilesCollectedMuteDurationInMinutes = 10 StorageLimitExceededSubject = "[Alert] You have exceeded your storage limit" ReferralSuccessfulTemplate = "successful_referral.html" @@ -113,6 +115,19 @@ func (c *EmailNotificationController) OnAccountUpgrade(userID int64) { } } +func (c *EmailNotificationController) OnSubscriptionCancelled(userID int64) { + user, err := c.UserRepo.Get(userID) + if err != nil { + log.Error("Could not find user to email", err) + return + } + log.Info(fmt.Sprintf("Emailing on subscription cancellation %d", user.ID)) + err = email.SendTemplatedEmail([]string{user.Email}, "vishnu@ente.io", "vishnu@ente.io", SubscriptionCancelledSubject, SubscriptionCancelledTemplate, nil, nil) + if err != nil { + log.Error("Error sending email", err) + } +} + func (c *EmailNotificationController) SendStorageLimitExceededMails() { if c.isSendingStorageLimitExceededMails { log.Info("Skipping sending storage limit exceeded mails as another instance is still running") diff --git a/server/pkg/controller/playstore.go b/server/pkg/controller/playstore.go index 49e5774d3b..4c155792c8 100644 --- a/server/pkg/controller/playstore.go +++ b/server/pkg/controller/playstore.go @@ -3,9 +3,10 @@ package controller import ( "context" "errors" + "os" + "github.com/ente-io/museum/pkg/controller/commonbilling" "github.com/ente-io/museum/pkg/repo/storagebonus" - "os" "github.com/ente-io/stacktrace" @@ -144,7 +145,7 @@ func (c *PlayStoreController) HandleNotification(notification playstore.Develope return stacktrace.Propagate(err, "") } case playstore.SubscriptionNotificationTypeCanceled: - err := c.BillingRepo.UpdateSubscriptionCancellationStatus(subscription.UserID, true) + err := c.CommonBillCtrl.OnSubscriptionCancelled(subscription.UserID) if err != nil { return stacktrace.Propagate(err, "") } diff --git a/server/pkg/controller/stripe.go b/server/pkg/controller/stripe.go index 9ce1b7e339..a8ad9cfdcf 100644 --- a/server/pkg/controller/stripe.go +++ b/server/pkg/controller/stripe.go @@ -503,7 +503,7 @@ func (c *StripeController) UpdateSubscription(stripeID string, userID int64) (en return ente.SubscriptionUpdateResponse{Status: "success"}, nil } -func (c *StripeController) UpdateSubscriptionCancellationStatus(userID int64, status bool) (ente.Subscription, error) { +func (c *StripeController) UpdateSubscriptionCancellationStatus(userID int64, shouldCancel bool) (ente.Subscription, error) { subscription, err := c.BillingRepo.GetUserSubscription(userID) if err != nil { // error sql.ErrNoRows not possible as user must at least have a free subscription @@ -513,24 +513,28 @@ func (c *StripeController) UpdateSubscriptionCancellationStatus(userID int64, st return ente.Subscription{}, stacktrace.Propagate(ente.ErrBadRequest, "") } - if subscription.Attributes.IsCancelled == status { + if subscription.Attributes.IsCancelled == shouldCancel { // no-op return subscription, nil } client := c.StripeClients[subscription.Attributes.StripeAccountCountry] params := &stripe.SubscriptionParams{ - CancelAtPeriodEnd: stripe.Bool(status), + CancelAtPeriodEnd: stripe.Bool(shouldCancel), } _, err = client.Subscriptions.Update(subscription.OriginalTransactionID, params) if err != nil { return ente.Subscription{}, stacktrace.Propagate(err, "") } - err = c.BillingRepo.UpdateSubscriptionCancellationStatus(userID, status) + if shouldCancel { + err = c.CommonBillCtrl.OnSubscriptionCancelled(userID) + } else { + err = c.BillingRepo.UpdateSubscriptionCancellationStatus(userID, false) + } if err != nil { return ente.Subscription{}, stacktrace.Propagate(err, "") } - subscription.Attributes.IsCancelled = status + subscription.Attributes.IsCancelled = shouldCancel return subscription, nil } @@ -703,7 +707,7 @@ func (c *StripeController) CancelSubAndDeleteCustomer(subscription ente.Subscrip return stacktrace.Propagate(err, "") } } - err = c.BillingRepo.UpdateSubscriptionCancellationStatus(subscription.UserID, true) + err = c.CommonBillCtrl.OnSubscriptionCancelled(subscription.UserID) if err != nil { return stacktrace.Propagate(err, "") }