~evanj/cms

ref: 8efa6eb4fd1aad49d40bb3850530c531add998da cms/internal/c/stripe/stripe.go -rw-r--r-- 2.5 KiB
8efa6eb4Evan M Jones WIP(stripe): *. 1 year, 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package stripe

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"git.sr.ht/~evanj/cms/internal/c"
	"git.sr.ht/~evanj/cms/internal/m/user"
	"git.sr.ht/~evanj/cms/internal/s/stripe"
	libstripe "github.com/stripe/stripe-go/v71"
	webhook "github.com/stripe/stripe-go/v71/webhook"
)

type StripeEndpoint struct {
	*c.Controller
	log                 *log.Logger
	db                  DBer
	stripeWebhookSecret string
}

type DBer interface {
	UserGetFromToken(token string) (user.User, error)
}

func New(c *c.Controller, l *log.Logger, db DBer, stripeWebhookSecret string) *StripeEndpoint {
	return &StripeEndpoint{c, l, db, stripeWebhookSecret}
}

func (s *StripeEndpoint) webhook(w http.ResponseWriter, r *http.Request) {
	// webhook from Stripe.
	bytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		s.ErrorString(w, r, http.StatusBadRequest, "failed to ready body")
		return
	}

	event, err := webhook.ConstructEvent(bytes, r.Header.Get("Stripe-Signature"), s.stripeWebhookSecret)
	if err != nil {
		s.log.Println("you do not have access")
		s.ErrorString(w, r, http.StatusForbidden, "you do not have access")
		return
	}

	switch event.Type {
	case "payment_intent.succeeded":
		var pi libstripe.PaymentIntent
		err := json.Unmarshal(event.Data.Raw, &pi)
		if err != nil {
			s.Error2(w, r, http.StatusBadRequest, fmt.Errorf("error parsing webhook JSON: %w\n", err))
			return
		}
		if pi.Customer == nil {
			s.ErrorString(w, r, http.StatusBadRequest, "no customer for payment")
			return
		}

		userToken, ok := pi.Customer.Metadata[stripe.KeyUserToken]
		if !ok {
			s.ErrorString(w, r, http.StatusBadRequest, "no user associated with customer")
			return
		}

		user, err := s.db.UserGetFromToken(userToken)
		if err != nil {
			s.ErrorString(w, r, http.StatusBadRequest, "no user for token")
			return
		}

		// TODO: Add payment to user/org.
		_ = user
		s.log.Println("success with getting user from PI")

	default:
		s.Error2(w, r, http.StatusBadRequest, fmt.Errorf("unexpected event type: %s\n", event.Type))
		return
	}

	s.log.Println("successfully completed stripe webhook")
	s.Redirect(w, r, "/")
}

func (s *StripeEndpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Handle users requests.
	switch r.URL.Path {
	case "/success":
		s.log.Println("redirect user success")
		s.Redirect(w, r, "/")
		return
	case "/error":
		s.log.Println("user error")
		s.ErrorString(w, r, http.StatusInternalServerError, "failed to process request: you have not been charged")
		return
	}

	s.webhook(w, r)
}