782 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			782 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"myapp/internal/cards"
 | |
| 	"myapp/internal/cards/encryption"
 | |
| 	"myapp/internal/models"
 | |
| 	"myapp/internal/urlsigner"
 | |
| 	"net/http"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/go-chi/chi/v5"
 | |
| 	"github.com/stripe/stripe-go/v79"
 | |
| 	"golang.org/x/crypto/bcrypt"
 | |
| )
 | |
| 
 | |
| type stripePayload struct {
 | |
| 	Currency      string `json:"currency"`
 | |
| 	Amount        string `json:"amount"`
 | |
| 	PaymentMethod string `json:"payment_method"`
 | |
| 	Email         string `json:"email"`
 | |
| 	CardBrand     string `json:"card_brand"`
 | |
| 	ExpiryMonth   int    `json:"expiry_month"`
 | |
| 	ExpiryYear    int    `json:"expiry_year"`
 | |
| 	LastFour      string `json:"last_four"`
 | |
| 	Plan          string `json:"plan"`
 | |
| 	ProductID     string `json:"product_id"`
 | |
| 	FirstName     string `json:"first_name"`
 | |
| 	LastName      string `json:"last_name"`
 | |
| }
 | |
| 
 | |
| type jsonResponse struct {
 | |
| 	OK      bool   `json:"ok"`
 | |
| 	Message string `json:"message,omitempty"`
 | |
| 	Content string `json:"content,omitempty"`
 | |
| 	ID      int    `json:"id,omitempty"`
 | |
| }
 | |
| 
 | |
| func (app *application) GetPaymentIntent(w http.ResponseWriter, r *http.Request) {
 | |
| 	var payload stripePayload
 | |
| 
 | |
| 	err := json.NewDecoder(r.Body).Decode(&payload)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		return // TODO: return a valid json
 | |
| 	}
 | |
| 
 | |
| 	amount, err := strconv.Atoi(payload.Amount)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		return // TODO: return a valid json
 | |
| 	}
 | |
| 
 | |
| 	card := cards.Card{
 | |
| 		Secret:   app.config.stripe.secret,
 | |
| 		Key:      app.config.stripe.key,
 | |
| 		Currency: payload.Currency,
 | |
| 	}
 | |
| 
 | |
| 	pi, msg, err := card.Charge(payload.Currency, amount)
 | |
| 	if err != nil {
 | |
| 		j := jsonResponse{
 | |
| 			OK:      false,
 | |
| 			Message: msg,
 | |
| 			Content: "",
 | |
| 		}
 | |
| 
 | |
| 		out, err := json.MarshalIndent(j, "", "    ")
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 		}
 | |
| 		w.Header().Set("Content-Type", "application/json")
 | |
| 		w.Write(out)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	out, err := json.MarshalIndent(pi, "", "    ")
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		return // TODO: return a valid json
 | |
| 	}
 | |
| 	w.Header().Set("Content-Type", "application/json")
 | |
| 	w.Write(out)
 | |
| }
 | |
| 
 | |
| func (app *application) GetWidgetByID(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)
 | |
| 	}
 | |
| 	out, err := json.MarshalIndent(widget, "", "    ")
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 	}
 | |
| 	w.Header().Set("Content-Type", "application/json")
 | |
| 	w.Write(out)
 | |
| }
 | |
| 
 | |
| func (app *application) CreateCustomerAndSubscribeToPlan(w http.ResponseWriter, r *http.Request) {
 | |
| 	var data stripePayload
 | |
| 
 | |
| 	err := json.NewDecoder(r.Body).Decode(&data)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	app.infoLog.Println(data.Email, data.LastFour, data.PaymentMethod, data.Plan)
 | |
| 
 | |
| 	card := cards.Card{
 | |
| 		Secret:   app.config.stripe.secret,
 | |
| 		Key:      app.config.stripe.key,
 | |
| 		Currency: data.Currency,
 | |
| 	}
 | |
| 
 | |
| 	okay := true
 | |
| 	var subscription *stripe.Subscription
 | |
| 	txnMsg := "Transaction successful"
 | |
| 
 | |
| 	stripeCustomer, msg, err := card.CreateCustomer(data.PaymentMethod, data.Email)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		okay = false
 | |
| 		txnMsg = msg
 | |
| 	}
 | |
| 
 | |
| 	if okay {
 | |
| 		subscription, err = card.SubscribeToPlan(
 | |
| 			stripeCustomer,
 | |
| 			data.Plan,
 | |
| 			data.Email,
 | |
| 			data.LastFour,
 | |
| 			"",
 | |
| 		)
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			okay = false
 | |
| 			txnMsg = "Error subscribing customer"
 | |
| 		}
 | |
| 		app.infoLog.Println("subscription id is", subscription.ID)
 | |
| 	}
 | |
| 
 | |
| 	if okay {
 | |
| 		productID, _ := strconv.Atoi(data.ProductID)
 | |
| 		customerID, err := app.SaveCustomer(data.FirstName, data.LastName, data.Email)
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// create a new txn
 | |
| 		amount, _ := strconv.Atoi(data.Amount)
 | |
| 		txn := models.Transaction{
 | |
| 			Amount:              amount,
 | |
| 			Currency:            "eur",
 | |
| 			LastFour:            data.LastFour,
 | |
| 			ExpiryMonth:         data.ExpiryMonth,
 | |
| 			ExpiryYear:          data.ExpiryYear,
 | |
| 			TransactionStatusID: 2,
 | |
| 			PaymentIntent:       subscription.ID,
 | |
| 			PaymentMethod:       data.PaymentMethod,
 | |
| 		}
 | |
| 		txnID, err := app.SaveTransaction(txn)
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		// create order
 | |
| 		order := models.Order{
 | |
| 			WidgetID:      productID,
 | |
| 			TransactionID: txnID,
 | |
| 			CustomerID:    customerID,
 | |
| 			StatusID:      1,
 | |
| 			Quantity:      1,
 | |
| 			Amount:        amount,
 | |
| 		}
 | |
| 
 | |
| 		_, err = app.SaveOrder(order)
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	resp := jsonResponse{
 | |
| 		OK:      okay,
 | |
| 		Message: txnMsg,
 | |
| 	}
 | |
| 
 | |
| 	out, err := json.MarshalIndent(resp, "", "    ")
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	w.Header().Set("Content-Type", "application/json")
 | |
| 	w.Write(out)
 | |
| }
 | |
| 
 | |
| 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
 | |
| }
 | |
| 
 | |
| func (app *application) CreateAuthToken(w http.ResponseWriter, r *http.Request) {
 | |
| 	var userInput struct {
 | |
| 		Email    string `json:"email"`
 | |
| 		Password string `json:"password"`
 | |
| 	}
 | |
| 
 | |
| 	err := app.readJSON(w, r, &userInput)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// get the user from the db by email, send error if invalid email
 | |
| 	user, err := app.DB.GetUserByEmail(userInput.Email)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.invalidCredentials(w)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// validate the password, send error if invalid password
 | |
| 	validPassword, err := app.passwordMatches(user.Password, userInput.Password)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.invalidCredentials(w)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !validPassword {
 | |
| 		app.invalidCredentials(w)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// generate the token
 | |
| 	token, err := models.GenerateToken(user.ID, 24*time.Hour, models.ScopeAuthentication)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// save to DB
 | |
| 	err = app.DB.InsertToken(token, user)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// send response
 | |
| 
 | |
| 	var payload struct {
 | |
| 		OK      bool          `json:"ok"`
 | |
| 		Message string        `json:"message"`
 | |
| 		Token   *models.Token `json:"authentication_token"`
 | |
| 	}
 | |
| 
 | |
| 	payload.OK = true
 | |
| 	payload.Message = fmt.Sprintf("token for %s created", userInput.Email)
 | |
| 	payload.Token = token
 | |
| 
 | |
| 	_ = app.writeJSON(w, http.StatusOK, payload)
 | |
| }
 | |
| 
 | |
| func (app *application) authenticateToken(r *http.Request) (*models.User, error) {
 | |
| 	authorizationHeader := r.Header.Get("Authorization")
 | |
| 	if authorizationHeader == "" {
 | |
| 		return nil, errors.New("no authorization header received")
 | |
| 	}
 | |
| 
 | |
| 	headerParts := strings.Split(authorizationHeader, " ")
 | |
| 	if len(headerParts) != 2 || headerParts[0] != "Bearer" {
 | |
| 		return nil, errors.New("no authorization header received")
 | |
| 	}
 | |
| 
 | |
| 	token := headerParts[1]
 | |
| 	if len(token) != 26 {
 | |
| 		return nil, errors.New("authentication token wrong size")
 | |
| 	}
 | |
| 
 | |
| 	// get the user from the tokens table
 | |
| 	user, err := app.DB.GetUserForToken(token)
 | |
| 	if err != nil {
 | |
| 		return nil, errors.New("no matching user found")
 | |
| 	}
 | |
| 
 | |
| 	return user, nil
 | |
| }
 | |
| 
 | |
| func (app *application) CheckAuthentication(w http.ResponseWriter, r *http.Request) {
 | |
| 	// validate the token, and get associated user
 | |
| 	user, err := app.authenticateToken(r)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.invalidCredentials(w)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// valid user
 | |
| 	var payload jsonResponse
 | |
| 	payload.OK = true
 | |
| 	payload.Message = fmt.Sprintf("authenticated user %s", user.Email)
 | |
| 	app.writeJSON(w, http.StatusOK, payload)
 | |
| }
 | |
| 
 | |
| func (app *application) VirtualTerminalPaymentSucceeded(w http.ResponseWriter, r *http.Request) {
 | |
| 	var txnData struct {
 | |
| 		PaymentAmount   int    `json:"amount"`
 | |
| 		PaymentCurrency string `json:"currency"`
 | |
| 		FirstName       string `json:"first_name"`
 | |
| 		LastName        string `json:"last_name"`
 | |
| 		Email           string `json:"email"`
 | |
| 		PaymentIntent   string `json:"payment_intent"`
 | |
| 		PaymentMethod   string `json:"payment_method"`
 | |
| 		BankReturnCode  string `json:"bank_return_code"`
 | |
| 		ExpiryMonth     int    `json:"expiry_month"`
 | |
| 		ExpiryYear      int    `json:"expiry_year"`
 | |
| 		LastFour        string `json:"last_four"`
 | |
| 	}
 | |
| 
 | |
| 	err := app.readJSON(w, r, &txnData)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	card := cards.Card{
 | |
| 		Secret: app.config.stripe.secret,
 | |
| 		Key:    app.config.stripe.key,
 | |
| 	}
 | |
| 
 | |
| 	pi, err := card.RetrievePaymentIntent(txnData.PaymentIntent)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	pm, err := card.GetPaymentMethod(txnData.PaymentMethod)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	txnData.LastFour = pm.Card.Last4
 | |
| 	txnData.ExpiryMonth = int(pm.Card.ExpMonth)
 | |
| 	txnData.ExpiryYear = int(pm.Card.ExpYear)
 | |
| 
 | |
| 	txn := models.Transaction{
 | |
| 		Amount:              txnData.PaymentAmount,
 | |
| 		Currency:            txnData.PaymentCurrency,
 | |
| 		LastFour:            txnData.LastFour,
 | |
| 		ExpiryMonth:         txnData.ExpiryMonth,
 | |
| 		ExpiryYear:          txnData.ExpiryYear,
 | |
| 		BankReturnCode:      pi.LatestCharge.ID,
 | |
| 		PaymentIntent:       txnData.PaymentIntent,
 | |
| 		PaymentMethod:       txnData.PaymentMethod,
 | |
| 		TransactionStatusID: 2,
 | |
| 	}
 | |
| 
 | |
| 	_, err = app.SaveTransaction(txn)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	app.writeJSON(w, http.StatusOK, txn)
 | |
| }
 | |
| 
 | |
| func (app *application) SendPasswordResetEmail(w http.ResponseWriter, r *http.Request) {
 | |
| 	var payload struct {
 | |
| 		Email string `json:"email"`
 | |
| 	}
 | |
| 
 | |
| 	err := app.readJSON(w, r, &payload)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// verify that email exists
 | |
| 	_, err = app.DB.GetUserByEmail(payload.Email)
 | |
| 	if err != nil {
 | |
| 		resp := jsonResponse{
 | |
| 			OK:      false,
 | |
| 			Message: "No matching email found on our system",
 | |
| 		}
 | |
| 		app.writeJSON(w, http.StatusAccepted, resp)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	link := fmt.Sprintf("%s/reset-password?email=%s", app.config.frontend, payload.Email)
 | |
| 	sign := urlsigner.Signer{
 | |
| 		Secret: []byte(app.config.secretkey),
 | |
| 	}
 | |
| 
 | |
| 	signedLink := sign.GenerateTokenFromString(link)
 | |
| 
 | |
| 	var data struct {
 | |
| 		Link string
 | |
| 	}
 | |
| 
 | |
| 	data.Link = signedLink
 | |
| 
 | |
| 	// send mail
 | |
| 	err = app.SendMail(
 | |
| 		"info@widgets.com",
 | |
| 		payload.Email,
 | |
| 		"Password Reset Request",
 | |
| 		"password-reset",
 | |
| 		data,
 | |
| 	)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	resp := jsonResponse{
 | |
| 		OK: true,
 | |
| 	}
 | |
| 
 | |
| 	app.writeJSON(w, http.StatusCreated, resp)
 | |
| }
 | |
| 
 | |
| func (app *application) ResetPassword(w http.ResponseWriter, r *http.Request) {
 | |
| 	var payload struct {
 | |
| 		Email    string `json:"email"`
 | |
| 		Password string `json:"password"`
 | |
| 	}
 | |
| 
 | |
| 	err := app.readJSON(w, r, &payload)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	encryptor := encryption.Encryption{
 | |
| 		Key: []byte(app.config.secretkey),
 | |
| 	}
 | |
| 
 | |
| 	realEmail, err := encryptor.Decrypt(payload.Email)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	user, err := app.DB.GetUserByEmail(realEmail)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	newHash, err := bcrypt.GenerateFromPassword([]byte(payload.Password), 12)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err = app.DB.UpdatePasswordForUser(user, string(newHash))
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	resp := jsonResponse{
 | |
| 		OK:      true,
 | |
| 		Message: "Password reset.",
 | |
| 	}
 | |
| 	app.writeJSON(w, http.StatusCreated, resp)
 | |
| }
 | |
| 
 | |
| func (app *application) AllSales(w http.ResponseWriter, r *http.Request) {
 | |
| 	var payload struct {
 | |
| 		PageSize    int `json:"page_size"`
 | |
| 		CurrentPage int `json:"page"`
 | |
| 	}
 | |
| 	err := app.readJSON(w, r, &payload)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	allSales, lastPage, totalRecords, err := app.DB.GetAllOrdersPaginated(
 | |
| 		false,
 | |
| 		payload.PageSize,
 | |
| 		payload.CurrentPage,
 | |
| 	)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var resp struct {
 | |
| 		CurrentPage  int             `json:"current_page"`
 | |
| 		PageSize     int             `json:"page_size"`
 | |
| 		LastPage     int             `json:"last_page"`
 | |
| 		TotalRecords int             `json:"total_records"`
 | |
| 		Orders       []*models.Order `json:"orders"`
 | |
| 	}
 | |
| 
 | |
| 	resp.CurrentPage = payload.CurrentPage
 | |
| 	resp.PageSize = payload.PageSize
 | |
| 	resp.LastPage = lastPage
 | |
| 	resp.TotalRecords = totalRecords
 | |
| 	resp.Orders = allSales
 | |
| 
 | |
| 	app.writeJSON(w, http.StatusOK, resp)
 | |
| }
 | |
| 
 | |
| func (app *application) AllSubscriptions(w http.ResponseWriter, r *http.Request) {
 | |
| 	var payload struct {
 | |
| 		PageSize    int `json:"page_size"`
 | |
| 		CurrentPage int `json:"page"`
 | |
| 	}
 | |
| 	err := app.readJSON(w, r, &payload)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	allSales, lastPage, totalRecords, err := app.DB.GetAllOrdersPaginated(
 | |
| 		true,
 | |
| 		payload.PageSize,
 | |
| 		payload.CurrentPage,
 | |
| 	)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var resp struct {
 | |
| 		CurrentPage  int             `json:"current_page"`
 | |
| 		PageSize     int             `json:"page_size"`
 | |
| 		LastPage     int             `json:"last_page"`
 | |
| 		TotalRecords int             `json:"total_records"`
 | |
| 		Orders       []*models.Order `json:"orders"`
 | |
| 	}
 | |
| 
 | |
| 	resp.CurrentPage = payload.CurrentPage
 | |
| 	resp.PageSize = payload.PageSize
 | |
| 	resp.LastPage = lastPage
 | |
| 	resp.TotalRecords = totalRecords
 | |
| 	resp.Orders = allSales
 | |
| 
 | |
| 	app.writeJSON(w, http.StatusOK, resp)
 | |
| }
 | |
| 
 | |
| func (app *application) GetSale(w http.ResponseWriter, r *http.Request) {
 | |
| 	id := chi.URLParam(r, "id")
 | |
| 	orderID, _ := strconv.Atoi(id)
 | |
| 
 | |
| 	order, err := app.DB.GetOrderByID(orderID)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 	app.writeJSON(w, http.StatusOK, order)
 | |
| }
 | |
| 
 | |
| func (app *application) RefundCharge(w http.ResponseWriter, r *http.Request) {
 | |
| 	var chargeToRefund struct {
 | |
| 		ID            int    `json:"id"`
 | |
| 		PaymentIntent string `json:"pi"`
 | |
| 		Amount        int    `json:"amount"`
 | |
| 		Currency      string `json:"currency"`
 | |
| 	}
 | |
| 
 | |
| 	err := app.readJSON(w, r, &chargeToRefund)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// validate
 | |
| 
 | |
| 	card := cards.Card{
 | |
| 		Secret:   app.config.stripe.secret,
 | |
| 		Key:      app.config.stripe.key,
 | |
| 		Currency: chargeToRefund.Currency,
 | |
| 	}
 | |
| 
 | |
| 	err = card.Refund(chargeToRefund.PaymentIntent, chargeToRefund.Amount)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// update status in DB
 | |
| 	err = app.DB.UpdateOrderStatus(chargeToRefund.ID, 2)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(
 | |
| 			w,
 | |
| 			r,
 | |
| 			errors.New("the charge was refunded, but the database could not be updated"),
 | |
| 		)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var resp jsonResponse
 | |
| 	resp.OK = true
 | |
| 	resp.Message = "Charge refunded"
 | |
| 
 | |
| 	app.writeJSON(w, http.StatusOK, resp)
 | |
| }
 | |
| 
 | |
| func (app *application) CancelSubscription(w http.ResponseWriter, r *http.Request) {
 | |
| 	var subToCancel struct {
 | |
| 		ID            int    `json:"id"`
 | |
| 		PaymentIntent string `json:"pi"`
 | |
| 		Currency      string `json:"currency"`
 | |
| 	}
 | |
| 
 | |
| 	err := app.readJSON(w, r, &subToCancel)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// validate
 | |
| 
 | |
| 	card := cards.Card{
 | |
| 		Secret:   app.config.stripe.secret,
 | |
| 		Key:      app.config.stripe.key,
 | |
| 		Currency: subToCancel.Currency,
 | |
| 	}
 | |
| 
 | |
| 	err = card.CancelSubscription(subToCancel.PaymentIntent)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// update status in DB
 | |
| 	err = app.DB.UpdateOrderStatus(subToCancel.ID, 3)
 | |
| 	if err != nil {
 | |
| 		app.badRequest(
 | |
| 			w,
 | |
| 			r,
 | |
| 			errors.New("the subscription was refunded, but the database could not be updated"),
 | |
| 		)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var resp jsonResponse
 | |
| 	resp.OK = true
 | |
| 	resp.Message = "Subscription canceled"
 | |
| 
 | |
| 	app.writeJSON(w, http.StatusOK, resp)
 | |
| }
 | |
| 
 | |
| func (app *application) AllUsers(w http.ResponseWriter, r *http.Request) {
 | |
| 	allUsers, err := app.DB.GetAllUsers()
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 	app.writeJSON(w, http.StatusOK, allUsers)
 | |
| }
 | |
| 
 | |
| func (app *application) OneUser(w http.ResponseWriter, r *http.Request) {
 | |
| 	id := chi.URLParam(r, "id")
 | |
| 	userID, _ := strconv.Atoi(id)
 | |
| 	user, err := app.DB.GetOneUser(userID)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 	app.writeJSON(w, http.StatusOK, user)
 | |
| }
 | |
| 
 | |
| func (app *application) EditUser(w http.ResponseWriter, r *http.Request) {
 | |
| 	id := chi.URLParam(r, "id")
 | |
| 	userID, _ := strconv.Atoi(id)
 | |
| 
 | |
| 	var user models.User
 | |
| 	err := app.readJSON(w, r, &user)
 | |
| 	if err != nil {
 | |
| 		app.errorLog.Println(err)
 | |
| 		app.badRequest(w, r, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if userID > 0 {
 | |
| 		err = app.DB.EditUser(user)
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			app.badRequest(w, r, err)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if user.Password != "" {
 | |
| 			newHash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 12)
 | |
| 			if err != nil {
 | |
| 				app.errorLog.Println(err)
 | |
| 				app.badRequest(w, r, err)
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			err = app.DB.UpdatePasswordForUser(user, string(newHash))
 | |
| 			if err != nil {
 | |
| 				app.errorLog.Println(err)
 | |
| 				app.badRequest(w, r, err)
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		newHash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 12)
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			app.badRequest(w, r, err)
 | |
| 			return
 | |
| 		}
 | |
| 		err = app.DB.AddUser(user, string(newHash))
 | |
| 		if err != nil {
 | |
| 			app.errorLog.Println(err)
 | |
| 			app.badRequest(w, r, err)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	var resp jsonResponse
 | |
| 	resp.OK = true
 | |
| 	app.writeJSON(w, http.StatusOK, resp)
 | |
| }
 |