126 lines
6.7 KiB
Go
126 lines
6.7 KiB
Go
package repo
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
|
|
"github.com/ente-io/stacktrace"
|
|
|
|
"github.com/awa/go-iap/appstore"
|
|
"github.com/awa/go-iap/playstore"
|
|
"github.com/ente-io/museum/ente"
|
|
"google.golang.org/api/androidpublisher/v3"
|
|
)
|
|
|
|
// BillingRepository defines the methods for inserting, updating and retrieving
|
|
// billing related entities from the underlying repository
|
|
type BillingRepository struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
// AddSubscription adds a subscription against a userID
|
|
func (repo *BillingRepository) AddSubscription(s ente.Subscription) (int64, error) {
|
|
var subscriptionID int64
|
|
err := repo.DB.QueryRow(`INSERT INTO subscriptions(user_id, storage, original_transaction_id, expiry_time, product_id, payment_provider, attributes)
|
|
VALUES($1, $2, $3, $4, $5, $6, $7)
|
|
RETURNING subscription_id`, s.UserID, s.Storage,
|
|
s.OriginalTransactionID, s.ExpiryTime, s.ProductID, s.PaymentProvider,
|
|
s.Attributes).Scan(&subscriptionID)
|
|
return subscriptionID, stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// UpdateSubscriptionExpiryTime updates the expiryTime of a subscription
|
|
func (repo *BillingRepository) UpdateSubscriptionExpiryTime(subscriptionID int64, expiryTime int64) error {
|
|
_, err := repo.DB.Exec(`UPDATE subscriptions SET expiry_time = $1 WHERE subscription_id = $2`, expiryTime, subscriptionID)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// UpdateSubscriptionCancellationStatus updates whether the user will cancel his subscription on period end
|
|
func (repo *BillingRepository) UpdateSubscriptionCancellationStatus(userID int64, status bool) error {
|
|
_, err := repo.DB.Exec(`UPDATE subscriptions SET attributes = jsonb_set(attributes, '{isCancelled}', $1::jsonb) WHERE user_id = $2`, status, userID)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// GetUserSubscription returns the last created subscription for a userID
|
|
func (repo *BillingRepository) GetUserSubscription(userID int64) (ente.Subscription, error) {
|
|
var s ente.Subscription
|
|
row := repo.DB.QueryRow(`SELECT subscription_id, user_id, product_id, storage, original_transaction_id, expiry_time, payment_provider, attributes FROM subscriptions WHERE user_id = $1`, userID)
|
|
err := row.Scan(&s.ID, &s.UserID, &s.ProductID, &s.Storage, &s.OriginalTransactionID, &s.ExpiryTime, &s.PaymentProvider, &s.Attributes)
|
|
return s, stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// GetSubscriptionForTransaction returns the subscription for a transactionID within a paymentProvider
|
|
func (repo *BillingRepository) GetSubscriptionForTransaction(transactionID string, paymentProvider ente.PaymentProvider) (ente.Subscription, error) {
|
|
var s ente.Subscription
|
|
row := repo.DB.QueryRow(`SELECT subscription_id, user_id, product_id, storage, original_transaction_id, expiry_time, payment_provider, attributes FROM subscriptions WHERE original_transaction_id = $1 AND payment_provider = $2`, transactionID, paymentProvider)
|
|
err := row.Scan(&s.ID, &s.UserID, &s.ProductID, &s.Storage, &s.OriginalTransactionID, &s.ExpiryTime, &s.PaymentProvider, &s.Attributes)
|
|
return s, stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// UpdateTransactionIDOnDeletion just append `userID:` before original transaction id on account deletion.
|
|
// This is to ensure that any subscription update isn't accidently applied to the deleted account and
|
|
// if user want to use same subscription in different ente account, they should be able to do that.
|
|
func (repo *BillingRepository) UpdateTransactionIDOnDeletion(userID int64) error {
|
|
_, err := repo.DB.Query(`update subscriptions SET original_transaction_id = user_id || ':' || original_transaction_id where original_transaction_id is not NULL and user_id= $1`, userID)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// ReplaceSubscription replaces a subscription with a new one
|
|
func (repo *BillingRepository) ReplaceSubscription(subscriptionID int64, s ente.Subscription) error {
|
|
_, err := repo.DB.Exec(`UPDATE subscriptions
|
|
SET storage = $2, original_transaction_id = $3, expiry_time = $4, product_id = $5, payment_provider = $6, attributes = $7
|
|
WHERE subscription_id = $1`,
|
|
subscriptionID, s.Storage, s.OriginalTransactionID, s.ExpiryTime, s.ProductID, s.PaymentProvider, s.Attributes)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// UpdateSubscription updates a subscription
|
|
func (repo *BillingRepository) UpdateSubscription(
|
|
subscriptionID int64,
|
|
storage int64,
|
|
paymentProvider ente.PaymentProvider,
|
|
transactionID string,
|
|
productID string,
|
|
expiryTime int64,
|
|
) error {
|
|
_, err := repo.DB.Exec(`UPDATE subscriptions
|
|
SET storage = $2, original_transaction_id = $3, expiry_time = $4, product_id = $5, payment_provider = $6
|
|
WHERE subscription_id = $1`,
|
|
subscriptionID, storage, transactionID, expiryTime, productID, paymentProvider)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// LogPlayStorePush logs a notification from PlayStore
|
|
func (repo *BillingRepository) LogPlayStorePush(userID int64, notification playstore.DeveloperNotification, verificationResponse androidpublisher.SubscriptionPurchase) error {
|
|
notificationJSON, _ := json.Marshal(notification)
|
|
responseJSON, _ := json.Marshal(verificationResponse)
|
|
_, err := repo.DB.Exec(`INSERT INTO subscription_logs(user_id, payment_provider, notification, verification_response) VALUES($1, $2, $3, $4)`,
|
|
userID, ente.PlayStore, notificationJSON, responseJSON)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// LogAppStorePush logs a notification from AppStore
|
|
func (repo *BillingRepository) LogAppStorePush(userID int64, notification appstore.SubscriptionNotification, verificationResponse appstore.IAPResponse) error {
|
|
notificationJSON, _ := json.Marshal(notification)
|
|
responseJSON, _ := json.Marshal(verificationResponse)
|
|
_, err := repo.DB.Exec(`INSERT INTO subscription_logs(user_id, payment_provider, notification, verification_response) VALUES($1, $2, $3, $4)`,
|
|
userID, ente.AppStore, notificationJSON, responseJSON)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// LogStripePush logs a notification from Stripe
|
|
func (repo *BillingRepository) LogStripePush(eventLog ente.StripeEventLog) error {
|
|
notificationJSON, _ := json.Marshal(eventLog.Event)
|
|
responseJSON, _ := json.Marshal(eventLog.StripeSubscription)
|
|
_, err := repo.DB.Exec(`INSERT INTO subscription_logs(user_id, payment_provider, notification, verification_response) VALUES($1, $2, $3, $4)`,
|
|
eventLog.UserID, ente.Stripe, notificationJSON, responseJSON)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
|
|
// LogStripePush logs a subscription modification by an admin
|
|
func (repo *BillingRepository) LogAdminTriggeredSubscriptionUpdate(r ente.UpdateSubscriptionRequest) error {
|
|
requestJSON, _ := json.Marshal(r)
|
|
_, err := repo.DB.Exec(`INSERT INTO subscription_logs(user_id, payment_provider, notification, verification_response) VALUES($1, $2, $3, '{}'::json)`,
|
|
r.UserID, r.PaymentProvider, requestJSON)
|
|
return stacktrace.Propagate(err, "")
|
|
}
|