package main import ( "fmt" "myapp/internal/cards" "myapp/internal/cards/encryption" "myapp/internal/models" "myapp/internal/urlsigner" "net/http" "strconv" "github.com/go-chi/chi/v5" ) func (app *application) Home(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "home", &templateData{}); err != nil { app.errorLog.Println(err) } } func (app *application) VirtualTerminal(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "terminal", &templateData{}); err != nil { app.errorLog.Println(err) } } type TransactionData struct { FirstName string LastName string Email string PaymentIntentID string PaymentMethodID string PaymentAmount int PaymentCurrency string LastFour string ExpiryMonth int ExpiryYear int BankReturnCode string } func (app *application) GetTransactionData(r *http.Request) (TransactionData, error) { var txnData TransactionData err := r.ParseForm() if err != nil { app.errorLog.Println(err) return txnData, err } firstName := r.Form.Get("first_name") lastName := r.Form.Get("last_name") email := r.Form.Get("cardholder_email") paymentIntent := r.Form.Get("payment_intent") paymentMethod := r.Form.Get("payment_method") paymentAmount := r.Form.Get("payment_amount") paymentCurrency := r.Form.Get("payment_currency") amount, _ := strconv.Atoi(paymentAmount) // TODO: validation of the data card := cards.Card{ Secret: app.config.stripe.secret, Key: app.config.stripe.key, } pi, err := card.RetrievePaymentIntent(paymentIntent) if err != nil { app.errorLog.Println(err) return txnData, err } pm, err := card.GetPaymentMethod(paymentMethod) if err != nil { app.errorLog.Println(err) return txnData, err } lastFour := pm.Card.Last4 expiryMonth := pm.Card.ExpMonth expiryYear := pm.Card.ExpYear txnData = TransactionData{ FirstName: firstName, LastName: lastName, Email: email, PaymentIntentID: paymentIntent, PaymentMethodID: paymentMethod, PaymentAmount: amount, PaymentCurrency: paymentCurrency, LastFour: lastFour, ExpiryMonth: int(expiryMonth), ExpiryYear: int(expiryYear), BankReturnCode: pi.LatestCharge.ID, } return txnData, nil } func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request) { // read posted data err := r.ParseForm() if err != nil { app.errorLog.Println(err) return } widgetID, _ := strconv.Atoi(r.Form.Get("product_id")) txnData, err := app.GetTransactionData(r) if err != nil { app.errorLog.Println(err) return } customerID, err := app.SaveCustomer(txnData.FirstName, txnData.LastName, txnData.Email) if err != nil { app.errorLog.Println(err) return } app.infoLog.Printf("custumer id: %d", customerID) transaction := models.Transaction{ Amount: txnData.PaymentAmount, Currency: txnData.PaymentCurrency, LastFour: txnData.LastFour, ExpiryMonth: txnData.ExpiryMonth, ExpiryYear: txnData.ExpiryYear, PaymentIntent: txnData.PaymentIntentID, PaymentMethod: txnData.PaymentMethodID, BankReturnCode: txnData.BankReturnCode, TransactionStatusID: 2, // TODO: use an enum } txnID, err := app.SaveTransaction(transaction) if err != nil { app.errorLog.Println(err) return } app.infoLog.Printf("transaction id: %d", txnID) order := models.Order{ WidgetID: widgetID, TransactionID: txnID, CustomerID: customerID, StatusID: 1, Quantity: 1, Amount: txnData.PaymentAmount, } orderID, err := app.SaveOrder(order) if err != nil { app.errorLog.Println(err) return } app.infoLog.Printf("order id: %d", orderID) app.Session.Put(r.Context(), "txn", txnData) http.Redirect(w, r, "/receipt", http.StatusSeeOther) } func (app *application) VirtualTerminalPaymentSucceeded(w http.ResponseWriter, r *http.Request) { txnData, err := app.GetTransactionData(r) if err != nil { app.errorLog.Println(err) return } transaction := models.Transaction{ Amount: txnData.PaymentAmount, Currency: txnData.PaymentCurrency, LastFour: txnData.LastFour, ExpiryMonth: txnData.ExpiryMonth, ExpiryYear: txnData.ExpiryYear, PaymentIntent: txnData.PaymentIntentID, PaymentMethod: txnData.PaymentMethodID, BankReturnCode: txnData.BankReturnCode, TransactionStatusID: 2, // TODO: use an enum } _, err = app.SaveTransaction(transaction) if err != nil { app.errorLog.Println(err) return } app.Session.Put(r.Context(), "txn", txnData) http.Redirect(w, r, "/virtual-terminal-receipt", http.StatusSeeOther) } func (app *application) Receipt(w http.ResponseWriter, r *http.Request) { txn := app.Session.Pop(r.Context(), "txn").(TransactionData) data := make(map[string]interface{}) data["txn"] = txn if err := app.renderTemplate(w, r, "receipt", &templateData{ Data: data, }); err != nil { app.errorLog.Println(err) } } func (app *application) VirtualTerminalReceipt(w http.ResponseWriter, r *http.Request) { txn := app.Session.Pop(r.Context(), "txn").(TransactionData) data := make(map[string]interface{}) data["txn"] = txn if err := app.renderTemplate(w, r, "virtual-terminal-receipt", &templateData{ Data: data, }); err != nil { app.errorLog.Println(err) } } func (app *application) SaveCustomer(firstName, lastName, email string) (int, error) { customer := models.Customer{ FirstName: firstName, LastName: lastName, Email: email, } id, err := app.DB.InsertCustomer(customer) if err != nil { return 0, err } return id, nil } func (app *application) SaveTransaction(txn models.Transaction) (int, error) { txnID, err := app.DB.InsertTransaction(txn) if err != nil { app.errorLog.Println(err) return 0, err } return txnID, nil } func (app *application) SaveOrder(order models.Order) (int, error) { id, err := app.DB.InsertOrder(order) if err != nil { app.errorLog.Println(err) return 0, err } return id, nil } // ChargeOnce displays the page to buy one widget func (app *application) ChargeOnce(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") widgetID, _ := strconv.Atoi(id) widget, err := app.DB.GetWidget(widgetID) if err != nil { app.errorLog.Println(err) } data := make(map[string]interface{}) data["widget"] = widget if err := app.renderTemplate(w, r, "buy-once", &templateData{ Data: data, }); err != nil { app.errorLog.Println(err) } } func (app *application) BronzePlan(w http.ResponseWriter, r *http.Request) { widget, err := app.DB.GetWidget(2) if err != nil { app.errorLog.Println(err) return } data := make(map[string]interface{}) data["widget"] = widget if err := app.renderTemplate(w, r, "bronze-plan", &templateData{ Data: data, }); err != nil { app.errorLog.Println(err) } } func (app *application) BronzePlanReceipt(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "receipt-plan", &templateData{}); err != nil { app.errorLog.Println(err) } } func (app *application) LoginPage(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "login", &templateData{}); err != nil { app.errorLog.Println(err) } } func (app *application) PostLoginPage(w http.ResponseWriter, r *http.Request) { app.Session.RenewToken(r.Context()) err := r.ParseForm() if err != nil { app.errorLog.Println(err) return } email := r.Form.Get("email") password := r.Form.Get("password") id, err := app.DB.Authenticate(email, password) if err != nil { http.Redirect(w, r, "/login", http.StatusSeeOther) return } app.Session.Put(r.Context(), "userID", id) http.Redirect(w, r, "/", http.StatusSeeOther) } func (app *application) Logout(w http.ResponseWriter, r *http.Request) { app.Session.Destroy(r.Context()) app.Session.RenewToken(r.Context()) http.Redirect(w, r, "/login", http.StatusSeeOther) } func (app *application) ForgotPassword(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "forgot-password", &templateData{}); err != nil { app.errorLog.Println(err) } } func (app *application) ShowResetPassword(w http.ResponseWriter, r *http.Request) { email := r.URL.Query().Get("email") theURL := r.RequestURI testURL := fmt.Sprintf("%s%s", app.config.frontend, theURL) signer := urlsigner.Signer{ Secret: []byte(app.config.secretkey), } valid := signer.VerifyToken(testURL) if !valid { app.errorLog.Println("Invalid url - tampering detected") return } // make sure not expired expired := signer.Expired(testURL, 10) if expired { app.errorLog.Println("Link expired") return } encryptor := encryption.Encryption{ Key: []byte(app.config.secretkey), } encryptedEmail, err := encryptor.Encrypt(email) if err != nil { app.errorLog.Println("Encryption failed", err) return } data := make(map[string]interface{}) data["email"] = encryptedEmail if err := app.renderTemplate(w, r, "reset-password", &templateData{ Data: data, }); err != nil { app.errorLog.Println(err) } } func (app *application) AllSales(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "all-sales", &templateData{}); err != nil { app.errorLog.Println(err) } } func (app *application) AllSubscriptions(w http.ResponseWriter, r *http.Request) { if err := app.renderTemplate(w, r, "all-subscriptions", &templateData{}); err != nil { app.errorLog.Println(err) } }