Skip to content

Commit

Permalink
Improving stripe flow
Browse files Browse the repository at this point in the history
  • Loading branch information
chew-z committed Feb 19, 2020
1 parent b627e53 commit 5dd5b87
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 75 deletions.
8 changes: 5 additions & 3 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,11 @@ func saveTokenToDB(token *firestoreToken) {
// TODO - two set operations - ?
_, err := firestoreClient.Doc(path).Set(ctx, token.token)
_, err = firestoreClient.Collection("users").Doc(token.user).Set(ctx, map[string]interface{}{
"userID": token.user,
"country": token.country,
"token_saved": time.Now(), // account created or logged in new browser
"userID": token.user,
"user_displayname": token.displayname,
"user_email": token.email,
"country": token.country,
"token_saved": time.Now(), // account created or logged in new browser
}, firestore.MergeAll)
if err != nil {
log.Printf("saveToken: Error saving token for %s %s", token.path, err.Error())
Expand Down
7 changes: 6 additions & 1 deletion handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var (
// Warning token will fail if you are changing scope (even if you narrow it down) so you might end up with bunch
// of useless stored tokens that will keep failing
// TODO - procedure for clearing useless token (users will have to re-authorize with Spotify)
auth = spotify.NewAuthenticator(redirectURI, spotify.ScopeUserReadPrivate, spotify.ScopeUserTopRead, spotify.ScopeUserLibraryRead, spotify.ScopeUserFollowRead, spotify.ScopeUserReadRecentlyPlayed, spotify.ScopePlaylistModifyPublic, spotify.ScopePlaylistModifyPrivate, spotify.ScopePlaylistReadCollaborative, spotify.ScopePlaylistReadPrivate) // clientChannel = make(chan *spotify.Client)
auth = spotify.NewAuthenticator(redirectURI, spotify.ScopeUserReadEmail, spotify.ScopeUserReadPrivate, spotify.ScopeUserTopRead, spotify.ScopeUserLibraryRead, spotify.ScopeUserFollowRead, spotify.ScopeUserReadRecentlyPlayed, spotify.ScopePlaylistModifyPublic, spotify.ScopePlaylistModifyPrivate, spotify.ScopePlaylistReadCollaborative, spotify.ScopePlaylistReadPrivate) // clientChannel = make(chan *spotify.Client)
)

/* statefull authorization handler using channels
Expand Down Expand Up @@ -95,6 +95,8 @@ func login(c *gin.Context) {
// save token to Firestore
var newTok firestoreToken
newTok.user = string(user.ID)
newTok.displayname = user.DisplayName
newTok.email = user.Email
newTok.country = string(user.Country)
newTok.path = endpoint
newTok.token = newToken
Expand All @@ -104,9 +106,12 @@ func login(c *gin.Context) {
// save necessary variables into session
session := sessions.Default(c)
// TODO - is it necessary and what would be optimal?

sessions.Default(c).Options(sessions.Options{MaxAge: sessionTimeout}) // make a session timeout after X seconds of inactivity
log.Printf("/login: %s from %s", string(user.ID), string(user.Country))
session.Set("user", string(user.ID))
session.Set("email", user.Email)
session.Set("displayname", user.DisplayName)
session.Set("country", string(user.Country))
session.Set("authPath", endpoint)
session.Set("uuid", uuid)
Expand Down
81 changes: 48 additions & 33 deletions payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import (

"github.com/gin-gonic/gin"
"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/checkout/session"
stripeSession "github.com/stripe/stripe-go/checkout/session"
"github.com/stripe/stripe-go/customer"
"github.com/stripe/stripe-go/webhook"
)

var ()

func handleCreateCheckoutSession(c *gin.Context) {
endpoint := c.Request.URL.Path
var req struct {
IsBuyingSticker bool `json:"isBuyingSticker"`
}
Expand All @@ -25,39 +26,53 @@ func handleCreateCheckoutSession(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

params := &stripe.CheckoutSessionParams{
PaymentMethodTypes: stripe.StringSlice([]string{
"card",
}),
SubscriptionData: &stripe.CheckoutSessionSubscriptionDataParams{
Items: []*stripe.CheckoutSessionSubscriptionDataItemsParams{
&stripe.CheckoutSessionSubscriptionDataItemsParams{
Plan: stripe.String(os.Getenv("SUBSCRIPTION_PLAN_ID")),
spotifyClient := clientMagic(c)
if spotifyClient != nil {
u, err := spotifyClient.CurrentUser()
if err != nil {
log.Panic(err)
}
userID := string(u.ID)
userName := u.DisplayName
userEmail := u.Email
log.Printf("User: %s, email: %s", userName, userEmail)
params := &stripe.CheckoutSessionParams{
PaymentMethodTypes: stripe.StringSlice([]string{
"card",
}),
SubscriptionData: &stripe.CheckoutSessionSubscriptionDataParams{
Items: []*stripe.CheckoutSessionSubscriptionDataItemsParams{
&stripe.CheckoutSessionSubscriptionDataItemsParams{
Plan: stripe.String(os.Getenv("SUBSCRIPTION_PLAN_ID")),
},
},
},
},
SuccessURL: stripe.String("https://" + os.Getenv("CUSTOM_DOMAIN") + "/paymentsuccess?session_id={CHECKOUT_SESSION_ID}"),
CancelURL: stripe.String("https://" + os.Getenv("CUSTOM_DOMAIN") + "/paymentcancel"),
}
if req.IsBuyingSticker {
params.LineItems = []*stripe.CheckoutSessionLineItemParams{
&stripe.CheckoutSessionLineItemParams{
Name: stripe.String("Donation to suka.yoga"),
Quantity: stripe.Int64(1),
Amount: stripe.Int64(1000),
Currency: stripe.String(string(stripe.CurrencyEUR)),
},
SuccessURL: stripe.String("https://" + os.Getenv("CUSTOM_DOMAIN") + "/paymentsuccess?session_id={CHECKOUT_SESSION_ID}"),
CancelURL: stripe.String("https://" + os.Getenv("CUSTOM_DOMAIN") + "/paymentcancel"),
ClientReferenceID: stripe.String(userID),
CustomerEmail: stripe.String(userEmail), //TODO - this is enverified email. Is is necessary? CustomerEmail or Customer not both
}
if req.IsBuyingSticker {
params.LineItems = []*stripe.CheckoutSessionLineItemParams{
&stripe.CheckoutSessionLineItemParams{
Name: stripe.String("Donation to suka.yoga"),
Quantity: stripe.Int64(1),
Amount: stripe.Int64(1000),
Currency: stripe.String(string(stripe.CurrencyEUR)),
},
}
}
}

session, err := session.New(params)
if err != nil {
log.Printf("session.New: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
stripeSess, err := stripeSession.New(params)
if err != nil {
log.Printf("session.New: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"checkoutSessionId": stripeSess.ID})
return
}
c.JSON(http.StatusOK, gin.H{"checkoutSessionId": session.ID})
c.JSON(http.StatusTeapot, gin.H{endpoint: "failed to find client"})
}

func handlePublicKey(c *gin.Context) {
Expand All @@ -75,15 +90,15 @@ func handleCheckoutSession(c *gin.Context) {

// Fetch the CheckoutSession object from your success page
// to get details about the order
session, err := session.Get(id, nil)
stripeSess, err := stripeSession.Get(id, nil)

if err != nil {
log.Printf("An error happened when getting the CheckoutSession %q from Stripe: %v", id, err)
c.JSON(http.StatusBadRequest, gin.H{"error": http.StatusText(http.StatusBadRequest)})
return
}

c.JSON(http.StatusOK, gin.H{"CheckoutSession": session})
c.JSON(http.StatusOK, gin.H{"CheckoutSession": stripeSess})
}

func handleWebhook(c *gin.Context) {
Expand Down Expand Up @@ -112,9 +127,9 @@ func handleWebhook(c *gin.Context) {
}

if event.GetObjectValue("display_items", "0", "custom") != "" &&
event.GetObjectValue("display_items", "0", "custom", "name") == "Pasha e-book" {
log.Printf("🔔 Customer is subscribed and bought an e-book! Send the e-book to %s", cust.Email)
event.GetObjectValue("display_items", "0", "custom", "name") == "Donation" {
log.Printf("🔔 Customer is subscribed and made a donation! Send the thank you note to %s", cust.Email)
} else {
log.Printf("🔔 Customer is subscribed but did not buy an e-book.")
log.Printf("🔔 Customer is subscribed but did not made a donation.")
}
}
6 changes: 4 additions & 2 deletions static/stripe.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const setupElements = function() {
})
.then((data) => {
stripe = Stripe(data.publicKey);
});
})
.catch(() => console.log("Can’t access " + "/public-key" + " response. Blocked by browser?"));
};

const createCheckoutSession = function(isBuyingSticker) {
Expand All @@ -29,7 +30,8 @@ const createCheckoutSession = function(isBuyingSticker) {
})
.then(function(data) {
checkoutSessionId = data.checkoutSessionId;
});
})
.catch(() => console.log("Can’t access " + "/create-checkout-session" + " response. Blocked by browser?"));
};
setupElements();
createCheckoutSession(false);
Expand Down
15 changes: 6 additions & 9 deletions structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,14 @@ type popularTrack struct {
// retrieve token form firestore and for some
//initialization
type firestoreToken struct {
user string // Spotify user ID
country string // The country of the user, as set in the user's account profile
path string // authorization path (gin routes group)
token *oauth2.Token // Spotify token
user string // Spotify user ID
displayname string
email string
country string // The country of the user, as set in the user's account profile
path string // authorization path (gin routes group)
token *oauth2.Token // Spotify token
}

// type timeZones struct {
// Time string `json:"time"`
// Zone []string `json:"zone"`
// }

type navigation struct {
Endpoint string
Title string
Expand Down
42 changes: 15 additions & 27 deletions templates/paymentsuccess.html
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
<!--paymentsuccess.html-->
<!--Embed the header.html template at this location-->
{{ template "header.html" .}}
<div class="sr-root">
<div class="sr-main">
<header class="sr-header">
<div class="sr-header__logo"></div>
</header>
<div class="sr-payment-summary completed-view">
<h1>Your test payment succeeded!</h1>
<h4>
View CheckoutSession response:</a>
</h4>
</div>
<div class="sr-section completed-view">
<div class="sr-callout">
<pre>

</pre>
</div>
</div>
<button onclick="window.location.href = '/payment';">Pay once more</button>
</div>
<div class="sr-content">
<div class="container">
<h1 class="h1">Your test payment succeeded!</h1>
<button class="btn btn-info" onclick="window.location.href = '/payment';">Pay once more</button>
<div class="container-md">
<h4 class="h4">
View CheckoutSession response:</a>
</h4>
<pre>

</pre>
</div>
</div>
<script>
Expand All @@ -32,12 +20,12 @@ <h4>
if (sessionId) {
fetch("/checkout-session?sessionId=" + sessionId)
.then((response) => {
console.log(response.status);
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
console.log(response.status);
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}).then((response) => {
return response.json()
}).then((data) => {
Expand Down

0 comments on commit 5dd5b87

Please sign in to comment.