udemy-go-web-2/cmd/web/handlers.go
2024-08-21 21:49:08 +02:00

382 lines
9.3 KiB
Go

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)
}
}