From 53ebad02ae5cd1ed4d11be9e0974d630f9931eb8 Mon Sep 17 00:00:00 2001
From: Immanuel Onyeka <immanuel@debian-BULLSEYE-live-builder-AMD64>
Date: Sat, 3 Feb 2024 18:54:15 -0500
Subject: [PATCH] Store price ID in subscriptions

---
 migrations/0_29092022_setup_tables.sql |  2 +
 skouter.go                             | 58 +++++++++++++++++++++++++-
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/migrations/0_29092022_setup_tables.sql b/migrations/0_29092022_setup_tables.sql
index 0bb57b9..1f799ad 100644
--- a/migrations/0_29092022_setup_tables.sql
+++ b/migrations/0_29092022_setup_tables.sql
@@ -63,6 +63,8 @@ CREATE TABLE subscription (
 	stripe_id 		VARCHAR(255) DEFAULT '',
 	user_id 		INT,
 	customer_id 	VARCHAR(255) NOT NULL,
+	price_id 	VARCHAR(255) NOT NULL,
+	// Key used by stripejs
 	client_secret 	VARCHAR(255) NOT NULL,
 	payment_status	VARCHAR(50) NOT NULL,
 	current_period_end 		INT DEFAULT 0,
diff --git a/skouter.go b/skouter.go
index 24f84d2..f9c3267 100644
--- a/skouter.go
+++ b/skouter.go
@@ -33,6 +33,7 @@ import (
 	"github.com/stripe/stripe-go/v76/subscription"
 	"github.com/stripe/stripe-go/v76/invoice"
 	"github.com/stripe/stripe-go/v76/paymentintent"
+	"github.com/stripe/stripe-go/v76/webhook"
 	"image"
 	_ "image/jpeg"
 	"image/png"
@@ -69,6 +70,7 @@ type Subscription struct {
 	UserId	int     `json:"userId"`
 	StripeId	string  `json:"stripeId"`
 	CustomerId	string  `json:"customerId"`
+	PriceId	string  `json:"priceId"`
 	Start	int     `json:"start"`
 	End	int     `json:"end"`
 	ClientSecret	string  `json:"clientSecret,omitempty"`
@@ -273,6 +275,8 @@ var feeTypes = []string{
 	"Other",
 }
 
+var standardPriceId = "price_1OZLK9BPMoXn2pf9kuTAf8rs"
+
 // Used to validate claim in JWT token body. Checks if user id is greater than
 // zero and time format is valid
 func (c UserClaims) Valid() error {
@@ -1291,6 +1295,7 @@ func (user *User) querySub(db *sql.DB) error {
 	stripe_id,
 	user_id,
 	customer_id,
+	price_id,
 	current_period_end,
 	current_period_start,
 	client_secret,
@@ -1304,6 +1309,7 @@ func (user *User) querySub(db *sql.DB) error {
 		&user.Sub.StripeId,
 		&user.Sub.UserId,
 		&user.Sub.CustomerId,
+		&user.Sub.PriceId,
 		&user.Sub.End,
 		&user.Sub.Start,
 		&user.Sub.ClientSecret,
@@ -1424,12 +1430,13 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) {
 		stripe_id,
 		user_id,
 		customer_id,
+		price_id,
 		current_period_end,
 		current_period_start,
 		client_secret,
 		payment_status
 	)
-	VALUES (?, ?, ?, ?, ?, ?, ?)
+	VALUES (?, ?, ?, ?, ?, ?, ?, ?)
 	RETURNING id
 	`
 	
@@ -1437,6 +1444,7 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) {
 		sub.StripeId,
 		sub.UserId,
 		sub.CustomerId,
+		sub.PriceId,
 		sub.End,
 		sub.Start,
 		sub.ClientSecret,
@@ -2946,7 +2954,7 @@ func createSubscription(cid string) (*stripe.Subscription, error) {
         Customer: stripe.String(cid),
         Items: []*stripe.SubscriptionItemsParams{
             {
-                Price: stripe.String("price_1OZLK9BPMoXn2pf9kuTAf8rs"),
+                Price: stripe.String(standardPriceId),
             },
         },
         PaymentSettings: paymentSettings,
@@ -2994,6 +3002,7 @@ func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 		user.Sub.UserId = user.Id
 		user.Sub.StripeId = s.ID
 		user.Sub.CustomerId = user.CustomerId
+		user.Sub.PriceId = standardPriceId
 		user.Sub.End = int(s.CurrentPeriodEnd)
 		user.Sub.Start = int(s.CurrentPeriodStart)
 		user.Sub.ClientSecret = s.LatestInvoice.PaymentIntent.ClientSecret
@@ -3019,6 +3028,44 @@ func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	
 }
 
+func invoicePaid(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+	b, err := io.ReadAll(r.Body)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		log.Printf("io.ReadAll: %v", err)
+		return
+	}
+	
+	event, err := webhook.ConstructEvent(b, r.Header.Get("Stripe-Signature"),
+	os.Getenv("STRIPE_SECRET_KEY"))
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		log.Printf("webhook.ConstructEvent: %v", err)
+		return
+	}
+
+	log.Println(event.Data)
+}
+
+func invoiceFailed(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+	b, err := io.ReadAll(r.Body)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		log.Printf("io.ReadAll: %v", err)
+		return
+	}
+	
+	event, err := webhook.ConstructEvent(b, r.Header.Get("Stripe-Signature"),
+	os.Getenv("STRIPE_SECRET_KEY"))
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		log.Printf("webhook.ConstructEvent: %v", err)
+		return
+	}
+
+	log.Println(event.Data)
+}
+
 func api(w http.ResponseWriter, r *http.Request) {
 	var args []string
 
@@ -3141,6 +3188,12 @@ func api(w http.ResponseWriter, r *http.Request) {
 		r.Method == http.MethodPost &&
 		guard(r, 1):
 		getPdf(w, db, r)
+	case match(p, "/api/stripe/invoice-paid", &args) &&
+		r.Method == http.MethodPost:
+		invoicePaid(w, db, r)
+	case match(p, "/api/stripe/invoice-payment-failed", &args) &&
+		r.Method == http.MethodPost:
+		invoiceFailed(w, db, r)
 	default:
 		http.Error(w, "Invalid route or token", 404)
 	}
@@ -3469,6 +3522,7 @@ func dev(args []string) {
 	os.Setenv("DBUser", "tester")
 	os.Setenv("DBPass", "test123")
 	stripe.Key = os.Getenv("STRIPE_SECRET_KEY")
+	standardPriceId = "price_1OZLK9BPMoXn2pf9kuTAf8rs"
 
 	db, err := sql.Open("mysql",
 		fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s?multiStatements=true",