|
|
@@ -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): |
|
|
|