diff --git a/handlers.go b/handlers.go index 51a11e6..f2eac91 100644 --- a/handlers.go +++ b/handlers.go @@ -25,11 +25,12 @@ import "github.com/stripe/stripe-go/v78/customer" import "github.com/stripe/stripe-go/v78/subscription" type templatedata struct { - AuthenticatedUser int32 - FormErrors map[string]string - Account Account - Prices []stripe.Price - ClientSecret string + AuthenticatedUser int32 + FormErrors map[string]string + Account Account + Prices []stripe.Price + ClientSecret string + ActiveSubscription bool } func favicon(w http.ResponseWriter, r *http.Request) { @@ -53,7 +54,7 @@ func authenticated_user(w http.ResponseWriter, r *http.Request) int32 { // check if the saved id exists in the database, otherwise it's a bad id and has to be removed from the cookies - exists := users.Exists_account(id) + exists := users.ExistsAccount(id) if !exists { session, _ := store.Get(r, "id") @@ -74,7 +75,8 @@ func home(w http.ResponseWriter, r *http.Request) { } id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) + activesubscription := subscriptions.HasActiveSubscription(id) text, err := template.ParseFiles("ui/base.html", "ui/index.html") if err != nil { @@ -85,7 +87,7 @@ func home(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: - err := text.Execute(w, templatedata{AuthenticatedUser: id, Account: account}) + err := text.Execute(w, templatedata{AuthenticatedUser: id, Account: account, ActiveSubscription: activesubscription}) if err != nil { log.Fatal(err) http.Error(w, "Internal Server Error", 500) @@ -174,12 +176,13 @@ func logout(w http.ResponseWriter, r *http.Request) { } id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) + activesubscription := subscriptions.HasActiveSubscription(id) switch r.Method { case http.MethodGet: - err := text.Execute(w, templatedata{AuthenticatedUser: id, Account: account}) + err := text.Execute(w, templatedata{AuthenticatedUser: id, Account: account, ActiveSubscription: activesubscription}) if err != nil { log.Fatal(err) http.Error(w, "Internal Server Error", 500) @@ -202,7 +205,7 @@ func register(w http.ResponseWriter, r *http.Request) { } id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) switch r.Method { case http.MethodGet: @@ -263,7 +266,7 @@ func account(w http.ResponseWriter, r *http.Request) { //} id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) fmt.Println(id, account) @@ -310,7 +313,7 @@ func deleteaccount(w http.ResponseWriter, r *http.Request) { func subscribe(w http.ResponseWriter, r *http.Request) { id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) params := &stripe.PriceListParams{} params.Limit = stripe.Int64(3) @@ -346,7 +349,7 @@ func subscribe(w http.ResponseWriter, r *http.Request) { func subscribe_stripe(w http.ResponseWriter, r *http.Request) { id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) params := &stripe.CustomerSessionParams{ Customer: stripe.String(account.StripeID), @@ -376,7 +379,7 @@ func subscribe_stripe(w http.ResponseWriter, r *http.Request) { func managebilling(w http.ResponseWriter, r *http.Request) { id := authenticated_user(w, r) - account, err := users.Get_account(id) + account, err := users.GetAccount(id) if err != nil { fmt.Println(err) } @@ -395,8 +398,6 @@ func managebilling(w http.ResponseWriter, r *http.Request) { } func webhooks(w http.ResponseWriter, r *http.Request) { - id := authenticated_user(w, r) - const MaxBodyBytes = int64(65536) r.Body = http.MaxBytesReader(w, r.Body, MaxBodyBytes) payload, err := ioutil.ReadAll(r.Body) @@ -435,7 +436,7 @@ func webhooks(w http.ResponseWriter, r *http.Request) { } // Then define and call a func to handle the successful payment intent. // handlePaymentIntentSucceeded(paymentIntent) - handle_checkout_session_completed(id, checkoutSession) + handle_checkout_session_completed(checkoutSession) case "payment_intent.succeeded": var paymentIntent stripe.PaymentIntent @@ -475,7 +476,7 @@ func webhooks(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func handle_checkout_session_completed(userid int32, checkoutsession stripe.CheckoutSession) error { +func handle_checkout_session_completed(checkoutsession stripe.CheckoutSession) error { //toprint, _ := json.MarshalIndent(checkoutSession, "", " ") //fmt.Println(string(toprint)) @@ -485,7 +486,6 @@ func handle_checkout_session_completed(userid int32, checkoutsession stripe.Chec return err } - fmt.Println(userid) fmt.Println(subscription.Customer.ID) //var status SubscriptionStatus @@ -508,7 +508,7 @@ func handle_checkout_session_completed(userid int32, checkoutsession stripe.Chec // status = paused //} - subscriptions.Insert(userid, subscription.ID, checkoutsession.ID, subscription.Status) + subscriptions.Insert(checkoutsession.Customer.ID, subscription.ID, checkoutsession.ID, subscription.Status) return nil } diff --git a/models.go b/models.go index 68e42ff..403d733 100644 --- a/models.go +++ b/models.go @@ -14,13 +14,13 @@ import "fmt" import "github.com/stripe/stripe-go/v78" import "github.com/stripe/stripe-go/v78/customer" -var ErrRoRecord = errors.New("no matching record found") +var ErrNoRecord = errors.New("no matching record found") var ErrInvalidCredentials = errors.New("invalid credentials") var ErrDuplicateEmail = errors.New("duplicate email") var ErrDuplicateUsername = errors.New("duplicate username") type Account struct { - Id int32 + ID int32 Username string Password []byte Color int32 @@ -31,19 +31,27 @@ type Account struct { StripeID string } -type SubscriptionStatus int32 +type SubscriptionStatus string const ( - incomplete SubscriptionStatus = iota - incomplete_expired - trialing - active - past_due - canceled - unpaid - paused + incomplete SubscriptionStatus = "incomplete" + incomplete_expired SubscriptionStatus = "incomplete_expired" + trialing SubscriptionStatus = "trialing" + active SubscriptionStatus = "active" + past_due SubscriptionStatus = "past_due" + canceled SubscriptionStatus = "canceled" + unpaid SubscriptionStatus = "unpaid" + paused SubscriptionStatus = "paused" ) +type Subscription struct { + ID int32 + AccountID int32 + StripeSubscriptionID string + StripeCheckoutID string + Status SubscriptionStatus +} + type Usermodel struct { DB *sql.DB } @@ -92,7 +100,7 @@ func (m *Usermodel) Insert(username string, password string, firstname string, l } func (m *Usermodel) Delete(id int32) error { - account, err := users.Get_account(id) + account, err := users.GetAccount(id) if account.StripeID != "" { result, err := customer.Del(account.StripeID, nil) @@ -113,15 +121,15 @@ func (m *Usermodel) Delete(id int32) error { return nil } -func (m *Usermodel) Get_account(id int32) (Account, error) { +func (m *Usermodel) GetAccount(id int32) (Account, error) { if id == 0 { - return Account{}, nil + return Account{}, ErrNoRecord } stmt := `SELECT id, username, password, color, firstname, lastname, email, created, stripe_id FROM accounts WHERE id = $1` row := m.DB.QueryRow(stmt, id) var account Account - err := row.Scan(&account.Id, &account.Username, &account.Password, &account.Color, &account.Firstname, &account.Lastname, &account.Email, &account.Created, &account.StripeID) + err := row.Scan(&account.ID, &account.Username, &account.Password, &account.Color, &account.Firstname, &account.Lastname, &account.Email, &account.Created, &account.StripeID) if err == sql.ErrNoRows { return Account{}, sql.ErrNoRows @@ -151,7 +159,7 @@ func (m *Usermodel) Authenticate(username string, password string) (int32, error return id, nil } -func (m *Usermodel) Exists_account(id int32) bool { +func (m *Usermodel) ExistsAccount(id int32) bool { var exists bool stmt := `SELECT EXISTS(SELECT 1 FROM accounts WHERE id = $1)` row := m.DB.QueryRow(stmt, id) @@ -165,20 +173,33 @@ func (m *Usermodel) Exists_account(id int32) bool { return exists } -func (m *SubscriptionModel) Insert(accountid int32, stripesubscriptionid string, stripecheckoutid string, status stripe.SubscriptionStatus) (int32, error) { +func (m *SubscriptionModel) Insert(stripeid string, stripesubscriptionid string, stripecheckoutid string, status stripe.SubscriptionStatus) (int32, error) { + var id int32 + stmt := `SELECT id FROM accounts WHERE stripe_id = $1` - - stmt := `INSERT INTO subscriptions (account_id, stripe_subscription_id, stripe_checkout_id, status) VALUES ($1, $2, $3, $4::subscription_status) RETURNING id` - - var insertid int32 - - row := m.DB.QueryRow(stmt, accountid, string(stripesubscriptionid), string(stripecheckoutid), string(status)) + row := m.DB.QueryRow(stmt, stripeid) if row.Err() != nil { fmt.Println(row.Err()) return 0, row.Err() } - err := row.Scan(&insertid) + err := row.Scan(&id) + if err != nil { + fmt.Println(err) + return 0, err + } + + stmt = `INSERT INTO subscriptions (account_id, stripe_subscription_id, stripe_checkout_id, status) VALUES ($1, $2, $3, $4::subscription_status) RETURNING id` + + var insertid int32 + + row = m.DB.QueryRow(stmt, id, string(stripesubscriptionid), string(stripecheckoutid), string(status)) + if row.Err() != nil { + fmt.Println(row.Err()) + return 0, row.Err() + } + + err = row.Scan(&insertid) if err != nil { fmt.Println(err) return 0, err @@ -198,3 +219,71 @@ func (m *SubscriptionModel) Delete(id int32) error { return nil } + +func (m *SubscriptionModel) GetSubscription(id int32) (Subscription, error) { + if id == 0 { + return Subscription{}, ErrNoRecord + } + + stmt := `SELECT id, account_id, stripe_subscription_id, stripe_checkout_id, status FROM subscriptions WHERE id = $1` + row := m.DB.QueryRow(stmt, id) + + var subscription Subscription + err := row.Scan(&subscription.ID, &subscription.AccountID, &subscription.StripeSubscriptionID, &subscription.StripeCheckoutID, &subscription.Status) + + if err == sql.ErrNoRows { + return Subscription{}, sql.ErrNoRows + } else if err != nil { + return Subscription{}, err + } + + fmt.Println(subscription.Status) + + return subscription, nil +} + +func (m *SubscriptionModel) GetSubscriptionsFromAccount(accountid int32) ([]Subscription, error) { + if accountid == 0 { + return nil, ErrNoRecord + } + + stmt := `SELECT id, account_id, stripe_subscription_id, stripe_checkout_id, status FROM subscriptions WHERE account_id = $1` + rows, err := m.DB.Query(stmt, accountid) + if err != nil { + return nil, err + } + defer rows.Close() + + var subscriptions []Subscription + for rows.Next() { + var subscription Subscription + err := rows.Scan(&subscription.ID, &subscription.AccountID, &subscription.StripeSubscriptionID, &subscription.StripeCheckoutID, &subscription.Status) + if err == sql.ErrNoRows { + return nil, sql.ErrNoRows + } else if err != nil { + return nil, err + } + + subscriptions = append(subscriptions, subscription) + } + + return subscriptions, nil +} + +func (m *SubscriptionModel) HasActiveSubscription(accountid int32) bool { + subscriptions, err := m.GetSubscriptionsFromAccount(accountid) + if err != nil { + fmt.Println(err) + return false + } + + for _, v := range subscriptions { + if v.Status == active { + return true + } else if v.Status == trialing { + return true + } + } + + return false +} diff --git a/static/Vollkorn-VariableFont_wght.ttf b/static/Vollkorn-VariableFont_wght.ttf new file mode 100644 index 0000000..188fd06 Binary files /dev/null and b/static/Vollkorn-VariableFont_wght.ttf differ diff --git a/static/login_24dp_FILL0_wght400_GRAD0_opsz24.svg b/static/login_24dp_FILL0_wght400_GRAD0_opsz24.svg new file mode 100644 index 0000000..1163dcb --- /dev/null +++ b/static/login_24dp_FILL0_wght400_GRAD0_opsz24.svg @@ -0,0 +1 @@ + diff --git a/static/style.css b/static/style.css index 353d7a3..d6a58a2 100644 --- a/static/style.css +++ b/static/style.css @@ -1,6 +1,7 @@ html { height: 100%; } + body { background-color: #3475CB; font-family: "Vollkorn"; @@ -13,7 +14,7 @@ body { } h1 { - font-size: 96px; + font-size: 6rem; margin: 0px; } @@ -62,7 +63,7 @@ main { box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); border-radius: 15px; padding: 30px 40px; - font-size: x-large; + font-size: 1.5rem; } .wrapper { @@ -76,7 +77,7 @@ main { } .wrapper h1 { - font-size: xx-large; + font-size: 1.5rem; text-align: center; } @@ -139,6 +140,10 @@ main { justify-content: center; } +input { + font-family: inherit; +} + footer { position: fixed; left: 0; diff --git a/ui/base.html b/ui/base.html index fe47c53..5d23b9d 100644 --- a/ui/base.html +++ b/ui/base.html @@ -3,15 +3,13 @@ Alfheim + - - - - - @@ -19,13 +17,15 @@