Browse Source

Return payment intent for new or existing subs

master
Immanuel Onyeka 1 year ago
parent
commit
f2dd73def0
3 changed files with 137 additions and 53 deletions
  1. +5
    -3
      grav-admin/user/js/registration/registration.vue
  2. +2
    -0
      migrations/0_29092022_setup_tables.sql
  3. +130
    -50
      skouter.go

+ 5
- 3
grav-admin/user/js/registration/registration.vue View File

@@ -58,7 +58,6 @@ function create(user) {
}

function intent(user) {
console.log(user)
return fetch(`/api/user/subscribe`,
{method: 'POST',
@@ -69,7 +68,10 @@ function intent(user) {
},
}).then(resp => {
if (resp.ok) {
return resp.json().then(u => { err.value = "" })
return resp.json().then(u => {
err.value = ""
console.log(u)
})
} else {
resp.text().then( e => err.value = e)
}
@@ -78,7 +80,7 @@ function intent(user) {

onMounted(() => {
getUser().then( u => {
intent(u)
if (u) intent(u)
})
})
</script>


+ 2
- 0
migrations/0_29092022_setup_tables.sql View File

@@ -33,6 +33,7 @@ CREATE TABLE user (
address INT NOT NULL,
password CHAR(64) NOT NULL,
verified BOOLEAN,
newsletter BOOLEAN DEFAULT 0,
branch_id INT DEFAULT NULL,
avatar BLOB(102400) NOT NULL DEFAULT 0,
letterhead BLOB(102400) NOT NULL DEFAULT 0,
@@ -62,6 +63,7 @@ CREATE TABLE subscription (
stripe_id VARCHAR(255) DEFAULT '',
user_id INT,
customer_id VARCHAR(255) NOT NULL,
client_secret VARCHAR(255) NOT NULL,
current_period_end INT DEFAULT 0,
current_period_start INT DEFAULT 0,
PRIMARY KEY (`id`),


+ 130
- 50
skouter.go View File

@@ -31,7 +31,8 @@ import (
"github.com/stripe/stripe-go/v76"
"github.com/stripe/stripe-go/v76/customer"
"github.com/stripe/stripe-go/v76/subscription"
// "github.com/stripe/stripe-go/v76/paymentintent"
"github.com/stripe/stripe-go/v76/invoice"
"github.com/stripe/stripe-go/v76/paymentintent"
"image"
_ "image/jpeg"
"image/png"
@@ -355,6 +356,25 @@ func match(path, pattern string, args *[]string) bool {
return true
}

func createToken(id int, role string) (*http.Cookie, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
UserClaims{Id: id, Role: role,
Exp: time.Now().Add(time.Minute * 30).Format(time.UnixDate)})

tokenStr, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
if err != nil {
log.Println("Token could not be signed: ", err, tokenStr)
return nil, errors.New("Token generation error.")
}

cookie := http.Cookie{Name: "skouter",
Value: tokenStr,
Path: "/",
Expires: time.Now().Add(time.Hour * 24)}

return &cookie, nil
}

func (estimate *Estimate) makeResults() []Result {
var results []Result
amortize := func(principle float64, rate float64, periods float64) int {
@@ -866,27 +886,16 @@ func login(w http.ResponseWriter, db *sql.DB, r *http.Request) {
return
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256,
UserClaims{Id: id, Role: role,
Exp: time.Now().Add(time.Minute * 30).Format(time.UnixDate)})

tokenStr, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
cookie, err := createToken(id, role)
if err != nil {
log.Println("Token could not be signed: ", err, tokenStr)
http.Error(w, "Token generation error.", http.StatusInternalServerError)
return
http.Error(w, err.Error(), 500)
}

cookie := http.Cookie{Name: "skouter",
Value: tokenStr,
Path: "/",
Expires: time.Now().Add(time.Hour * 24)}
http.SetCookie(w, &cookie)
_, err = w.Write([]byte(tokenStr))
http.SetCookie(w, cookie)
_, err = w.Write([]byte(cookie.Value))
if err != nil {
http.Error(w,
"Could not complete token write.",
http.StatusInternalServerError)
http.Error(w, "Could not complete token write.",
http.StatusInternalServerError)
}
}

@@ -950,6 +959,7 @@ func guard(r *http.Request, required int) bool {
if roles[claims.Role] < required {
return false
}

return true
}
@@ -1251,7 +1261,8 @@ func querySub(db *sql.DB, id int) (Subscription, error) {
user_id,
customer_id,
current_period_end,
current_period_start
current_period_start,
client_secret
FROM subscription WHERE id = ?
`
row := db.QueryRow(query, id)
@@ -1262,6 +1273,7 @@ func querySub(db *sql.DB, id int) (Subscription, error) {
&s.CustomerId,
&s.End,
&s.Start,
&s.ClientSecret,
)

return s, err
@@ -1277,7 +1289,8 @@ func (user *User) querySub(db *sql.DB) error {
user_id,
customer_id,
current_period_end,
current_period_start
current_period_start,
client_secret
FROM subscription WHERE user_id = ?
`
row := db.QueryRow(query, user.Id)
@@ -1289,6 +1302,7 @@ func (user *User) querySub(db *sql.DB) error {
&user.Sub.CustomerId,
&user.Sub.End,
&user.Sub.Start,
&user.Sub.ClientSecret,
)

return err
@@ -1397,6 +1411,7 @@ func insertUser(db *sql.DB, user User) (int, error) {
// Insert user returning it's ID or any error
func (sub *Subscription) insertSub(db *sql.DB) (error) {
var query string
var row *sql.Row
var err error

query = `INSERT INTO subscription
@@ -1405,17 +1420,49 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) {
user_id,
customer_id,
current_period_end,
current_period_start
current_period_start,
client_secret
)
VALUES (?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?)
RETURNING id
`
_, err = db.Exec(query,
row = db.QueryRow(query,
sub.StripeId,
sub.UserId,
sub.CustomerId,
sub.End,
sub.Start,
sub.ClientSecret,
)

err = row.Scan(&sub.Id)
return err
}

func (sub *Subscription) updateSubSecret(db *sql.DB) error {
var query string
var err error

query = `UPDATE subscription SET
client_secret = ?
WHERE id = ?
`
s, err := subscription.Get(sub.StripeId, &stripe.SubscriptionParams{})
if err != nil { return err }
i, err := invoice.Get(s.LatestInvoice.ID, &stripe.InvoiceParams{})
if err != nil { return err }
p, err := paymentintent.Get(i.PaymentIntent.ID,
&stripe.PaymentIntentParams{})
if err != nil { return err }

_, err = db.Exec(query,
p.ClientSecret,
sub.Id,
)

return err
@@ -1435,8 +1482,11 @@ func (user *User) updateCustomerId(db *sql.DB, cid string) (error) {
cid,
user.Id,
)
if err != nil { return err }
user.CustomerId = cid

return err
return nil
}

func updateAddress(address Address, db *sql.DB) error {
@@ -2869,25 +2919,9 @@ stripe.Customer, error) {
return *result, err
}

func createSubscription(w http.ResponseWriter, db *sql.DB, r *http.Request) {
claims, err := getClaims(r)
user, err := queryUser(db, claims.Id)
if err != nil {
w.WriteHeader(422)
return
}
var name string = user.FirstName + " " + user.LastName
c, err := createCustomer(name, user.Email, user.Address)
if err != nil {
http.Error(w, err.Error(), 422)
return
}
err = user.updateCustomerId(db, c.ID)
// Initiates a new standard subscription using a given customer ID
func createSubscription(cid string) (*stripe.Subscription, error) {

// Automatically save the payment method to the subscription
// when the first payment is successful.
paymentSettings := &stripe.SubscriptionPaymentSettingsParams{
@@ -2898,7 +2932,7 @@ func createSubscription(w http.ResponseWriter, db *sql.DB, r *http.Request) {
// latest invoice and that invoice's payment_intent
// so we can pass it to the front end to confirm the payment
subscriptionParams := &stripe.SubscriptionParams{
Customer: stripe.String(c.ID),
Customer: stripe.String(cid),
Items: []*stripe.SubscriptionItemsParams{
{
Price: stripe.String("price_1OZLK9BPMoXn2pf9kuTAf8rs"),
@@ -2910,12 +2944,58 @@ func createSubscription(w http.ResponseWriter, db *sql.DB, r *http.Request) {
subscriptionParams.AddExpand("latest_invoice.payment_intent")
s, err := subscription.New(subscriptionParams)
if err != nil {
http.Error(w, err.Error(), 500)
return s, err
}

func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) {
claims, err := getClaims(r)
user, err := queryUser(db, claims.Id)
if err != nil {
w.WriteHeader(422)
return
}
json.NewEncoder(w).Encode(s)
user.querySub(db)
var name string = user.FirstName + " " + user.LastName
if user.CustomerId == "" {
c, err := createCustomer(name, user.Email, user.Address)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
err = user.updateCustomerId(db, c.ID)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
if user.Sub.Id == 0 {
s, err := createSubscription(user.CustomerId)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
user.Sub.UserId = user.Id
user.Sub.StripeId = s.ID
user.Sub.CustomerId = user.CustomerId
user.Sub.End = int(s.CurrentPeriodEnd)
user.Sub.Start = int(s.CurrentPeriodStart)
user.Sub.ClientSecret = s.LatestInvoice.PaymentIntent.ClientSecret
user.Sub.insertSub(db)
json.NewEncoder(w).Encode(user.Sub)
} else {
json.NewEncoder(w).Encode(user.Sub)
}
// Should check that subscription is still valid and has payment intent
// here
}

func api(w http.ResponseWriter, r *http.Request) {
@@ -2991,7 +3071,7 @@ func api(w http.ResponseWriter, r *http.Request) {
case match(p, "/api/user/subscribe", &args) &&
r.Method == http.MethodPost &&
guard(r, 1):
createSubscription(w, db, r)
subscribe(w, db, r)
case match(p, "/api/fees", &args) &&
r.Method == http.MethodGet &&
guard(r, 1):


Loading…
Cancel
Save