From e1863709dfb60e842eee66a30302b930b4a8e3fd Mon Sep 17 00:00:00 2001 From: Colin Henry Date: Wed, 9 Oct 2019 08:56:57 -0700 Subject: [PATCH] got basic flow of subscription working. next to tie it together --- .gitignore | 2 + auth/callback.go | 2 +- auth/config.go | 26 +++++---- auth/login.go | 2 +- auth/logout.go | 27 ++++++++-- auth/middleware.go | 2 +- auth/service.go | 13 +++++ auth/session.go | 4 +- auth/user.go | 23 +++----- cmd/sub-demo/main.go | 6 ++- cmd/sub-demo/run.sh | 2 + cmd/sub-demo/subscription.html | 98 ++++++++++++++++++++++++++++++++-- cmd/sub-demo/user.html | 13 ++++- go.mod | 3 +- go.sum | 20 ++++++- payments/config.go | 3 ++ payments/middleware.go | 4 +- payments/service.go | 67 ++++++++++++++++++++++- 18 files changed, 268 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index 1d74e21..21be33c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +cmd/sub-demo/sub-demo +cmd/auth-demo/auth-demo .vscode/ diff --git a/auth/callback.go b/auth/callback.go index 0b02544..06266b6 100644 --- a/auth/callback.go +++ b/auth/callback.go @@ -11,7 +11,7 @@ import ( func NewCallbackHandler(c Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - session, err := Store.Get(r, "auth-session") + session, err := Store.Get(r, SessionName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/auth/config.go b/auth/config.go index a4c731b..e53329c 100644 --- a/auth/config.go +++ b/auth/config.go @@ -6,20 +6,26 @@ import ( ) type Config struct { - Domain string - ClientID string - ClientSecret string - CallbackURL string - RedirectURL string + Domain string + ClientID string + ClientSecret string + ManagementClientID string + ManagementClientSecret string + + CallbackURL string + RedirectURL string } func FromEnv() Config { return Config{ - Domain: os.Getenv("AUTH_DOMAIN"), - ClientID: os.Getenv("AUTH_CLIENT_ID"), - ClientSecret: os.Getenv("AUTH_CLIENT_SECRET"), - CallbackURL: os.Getenv("AUTH_CALLBACK_URL"), - RedirectURL: "/user", + Domain: os.Getenv("AUTH_DOMAIN"), + ClientID: os.Getenv("AUTH_CLIENT_ID"), + ClientSecret: os.Getenv("AUTH_CLIENT_SECRET"), + ManagementClientID: os.Getenv("AUTH_MGMT_CLIENT_ID"), + ManagementClientSecret: os.Getenv("AUTH_MGMT_CLIENT_SECRET"), + + CallbackURL: os.Getenv("AUTH_CALLBACK_URL"), + RedirectURL: "/user", } } diff --git a/auth/login.go b/auth/login.go index 673248a..5312158 100644 --- a/auth/login.go +++ b/auth/login.go @@ -19,7 +19,7 @@ func NewLoginHandler(c Config) http.HandlerFunc { } state := base64.StdEncoding.EncodeToString(b) - session, err := Store.Get(r, "auth-session") + session, err := Store.Get(r, SessionName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/auth/logout.go b/auth/logout.go index 75c66ac..497851a 100644 --- a/auth/logout.go +++ b/auth/logout.go @@ -7,20 +7,37 @@ import ( func LogoutHandler(w http.ResponseWriter, r *http.Request) { + if cook, err := r.Cookie(SessionName); err == nil { + cook.MaxAge = -1 + http.SetCookie(w, cook) + } + domain := "dev-pb4s8m55.auth0.com" - var Url *url.URL - Url, err := url.Parse("https://" + domain) + // var Url *url.URL + URL, err := url.Parse("https://" + domain) if err != nil { panic(err.Error()) } - Url.Path += "/v2/logout" + session, err := Store.Get(r, SessionName) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + session.Options.MaxAge = -1 + + err = session.Save(r, w) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + URL.Path += "/v2/logout" parameters := url.Values{} parameters.Add("returnTo", "http://localhost:3000") parameters.Add("client_id", "ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9") - Url.RawQuery = parameters.Encode() + URL.RawQuery = parameters.Encode() - http.Redirect(w, r, Url.String(), http.StatusTemporaryRedirect) + http.Redirect(w, r, URL.String(), http.StatusTemporaryRedirect) } diff --git a/auth/middleware.go b/auth/middleware.go index 03c6105..4e918b8 100644 --- a/auth/middleware.go +++ b/auth/middleware.go @@ -4,7 +4,7 @@ import "net/http" func IsAuthenticated(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - session, err := Store.Get(r, "auth-session") + session, err := Store.Get(r, SessionName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/auth/service.go b/auth/service.go index d7e0cf3..ef01116 100644 --- a/auth/service.go +++ b/auth/service.go @@ -5,6 +5,7 @@ import ( "github.com/codegangsta/negroni" jch_http "github.com/jchenry/jchenry/http" + "gopkg.in/auth0.v1/management" ) func Service(c Config) ServiceInstance { @@ -25,3 +26,15 @@ func (si ServiceInstance) Register(uriBase string, s *jch_http.Server) { negroni.Wrap(http.HandlerFunc(UserHandler)), )) } + +func (si ServiceInstance) UpdateUser(u User) error { + + m, err := management.New(si.c.Domain, si.c.ManagementClientID, si.c.ManagementClientSecret) + if err != nil { + return err + } + + um := management.NewUserManager(m) + + return um.Update(u.ID, &management.User{AppMetadata: u.Apps}) +} diff --git a/auth/session.go b/auth/session.go index 2381940..287d1b7 100644 --- a/auth/session.go +++ b/auth/session.go @@ -6,14 +6,14 @@ import ( "github.com/gorilla/sessions" ) +const SessionName = "auth-session" + var ( Store *sessions.FilesystemStore ) func Init() error { Store = sessions.NewFilesystemStore("", []byte("something-very-secret")) - gob.Register(map[string]interface{}{}) gob.Register(User{}) - return nil } diff --git a/auth/user.go b/auth/user.go index 0e7a977..225d4ff 100644 --- a/auth/user.go +++ b/auth/user.go @@ -8,7 +8,7 @@ import ( func UserHandler(w http.ResponseWriter, r *http.Request) { - session, err := Store.Get(r, "auth-session") + session, err := Store.Get(r, SessionName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -18,23 +18,16 @@ func UserHandler(w http.ResponseWriter, r *http.Request) { } type User struct { - Email string `json:"email"` - FirstName string `json:"given_name"` - LastName string `json:"family_name"` - Picture string `json:"picture"` - Nickname string `json:"nickname"` - AppMetadata AppMetadata `json:"app_metadata"` + ID string `json:"sub"` + Email string `json:"email"` + FirstName string `json:"given_name"` + LastName string `json:"family_name"` + Picture string `json:"picture"` + Nickname string `json:"nickname"` + Apps map[string]interface{} `json:"app_metadata,omitempty"` //UserMetadata UserMetadata `json:"user_metadata"` } -type AppMetadata struct { - Apps map[string]string // an association between the unique applicationID and the tenantID that the user is associated with - // Apps []struct { - // ApplicationID string - // TenantID string - // } -} - // type UserMetadata struct { // } diff --git a/cmd/sub-demo/main.go b/cmd/sub-demo/main.go index 77ccd7f..ac33afe 100644 --- a/cmd/sub-demo/main.go +++ b/cmd/sub-demo/main.go @@ -18,10 +18,12 @@ func main() { func StartServer() { auth.PrintConfig() payments.PrintConfig() + + auth_service := auth.Service(auth.FromEnv()) s := jch_http.NewServer(negroni.New()). Static("/public/*filepath", http.Dir("public/")). - Service("", auth.Service(auth.FromEnv())). - Service("", payments.Service(payments.FromEnv())). + Service("", auth_service). + Service("", payments.Service(payments.FromEnv(), &auth_service)). GET("/", "", http.HandlerFunc(HomeHandler)) port := os.Getenv("PORT") diff --git a/cmd/sub-demo/run.sh b/cmd/sub-demo/run.sh index 85406e3..c95d2ac 100755 --- a/cmd/sub-demo/run.sh +++ b/cmd/sub-demo/run.sh @@ -3,6 +3,8 @@ AUTH_DOMAIN="https://dev-pb4s8m55.auth0.com/" \ AUTH_CLIENT_ID="ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9" \ AUTH_CLIENT_SECRET="NFC5KYeM9GA2z0ptvzKPo9jmkQDRjx_WcsWyK0hzOJmr1CykS9cEmTcNh0-hKiMd" \ AUTH_CALLBACK_URL="http://localhost:3000/callback" \ +AUTH_MGMT_CLIENT_ID="0SpgXDo7HleFZ6NH9ds2t2vkntEzgYqy" \ +AUTH_MGMT_CLIENT_SECRET="DhOE1JqO7A2uosadjuyCluK5P3NlxOf4V9mPkEDy4gDO_lYnMffzYfVpgcINvzfr" \ STRIPE_KEY="sk_test_3yIcJl5ev3WfFZ4HNbTMqWv800B26e0c4V" \ STRIPE_PRODUCT_ID="prod_FtzugcD89mNVhp" \ ./sub-demo \ No newline at end of file diff --git a/cmd/sub-demo/subscription.html b/cmd/sub-demo/subscription.html index e0df646..f30daa1 100644 --- a/cmd/sub-demo/subscription.html +++ b/cmd/sub-demo/subscription.html @@ -10,26 +10,114 @@ + +
{{.Product.Name}} -
+
{{range .Plans}}
- -
{{end}} + +
+ +
+ +
+ + + +
+ + +
+ \ No newline at end of file diff --git a/cmd/sub-demo/user.html b/cmd/sub-demo/user.html index e327ed3..78cfe44 100644 --- a/cmd/sub-demo/user.html +++ b/cmd/sub-demo/user.html @@ -1,4 +1,5 @@ + @@ -11,15 +12,25 @@ +
+ + \ No newline at end of file diff --git a/go.mod b/go.mod index fd96794..1aa2e46 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,14 @@ go 1.13 require ( github.com/codegangsta/negroni v1.0.0 github.com/coreos/go-oidc v2.1.0+incompatible - github.com/gorilla/mux v1.7.3 github.com/gorilla/sessions v1.2.0 github.com/julienschmidt/httprouter v1.2.0 github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect + github.com/stretchr/testify v1.4.0 // indirect github.com/stripe/stripe-go v63.4.0+incompatible golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 + gopkg.in/auth0.v1 v1.2.7 gopkg.in/square/go-jose.v2 v2.3.1 // indirect rsc.io/dbstore v0.1.1 ) diff --git a/go.sum b/go.sum index 51dff60..b5fb1c6 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,27 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9 h1:VE0eMvNSQI72dADsq4gm5KpNPmt97WgqneTfaS5MWrs= +github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9/go.mod h1:ItsOiHl4XeMOV3rzbZqQRjLc3QQxbE6391/9iNG7rE8= github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stripe/stripe-go v63.4.0+incompatible h1:zzZR004GZ/si7nyckn4NBhoQOViUu5VJ/sA7NT7oTSs= github.com/stripe/stripe-go v63.4.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -25,16 +32,25 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/auth0.v1 v1.2.7 h1:9UCE5rKFL60rqQENmmJaGdNu7/aby8r8wVcJ83Vj5oU= +gopkg.in/auth0.v1 v1.2.7/go.mod h1:1FRtMXwYDgygZcO7Of7kj/I4mf9UjHGhMHUOqNT0d0M= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= rsc.io/dbstore v0.1.1 h1:LI4gBJUwbejn0wHJWe0KTwgCM33zUVP3BsNz5y2fkEE= rsc.io/dbstore v0.1.1/go.mod h1:zI7k1PCSLg9r/T2rBM4E/SctbGmqdtt3kjQSemVh1Rs= rsc.io/sqlite v0.5.0 h1:HG63YxeP0eALjqorwnJ9ENxUUOUR6NYJ4FHEKFJ7aVk= diff --git a/payments/config.go b/payments/config.go index 0c5c310..23df01c 100644 --- a/payments/config.go +++ b/payments/config.go @@ -8,12 +8,15 @@ import ( type Config struct { StripeKey string StripeProductID string + RedirectURL string + TenantSetup func(subscriptionID, customerID string) (tenantID string) } func FromEnv() Config { return Config{ StripeKey: os.Getenv("STRIPE_KEY"), StripeProductID: os.Getenv("STRIPE_PRODUCT_ID"), + RedirectURL: "/", } } diff --git a/payments/middleware.go b/payments/middleware.go index cb90015..59d5c86 100644 --- a/payments/middleware.go +++ b/payments/middleware.go @@ -9,7 +9,7 @@ import ( func HasTenantAndSubscription(productID string) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - session, err := auth.Store.Get(r, "auth-session") + session, err := auth.Store.Get(r, auth.SessionName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -17,7 +17,7 @@ func HasTenantAndSubscription(productID string) func(w http.ResponseWriter, r *h if u, ok := session.Values["profile"]; ok { user := u.(auth.User) - if _, exist := user.AppMetadata.Apps[productID]; !exist { + if _, exist := user.Apps[productID]; exist { next(w, r) } else { http.Redirect(w, r, "/subscription", http.StatusSeeOther) diff --git a/payments/service.go b/payments/service.go index eb8bd58..e0fc54e 100644 --- a/payments/service.go +++ b/payments/service.go @@ -1,6 +1,7 @@ package payments import ( + "fmt" "net/http" "github.com/codegangsta/negroni" @@ -8,30 +9,38 @@ import ( jch_http "github.com/jchenry/jchenry/http" "github.com/stripe/stripe-go" "github.com/stripe/stripe-go/client" + "github.com/stripe/stripe-go/customer" "github.com/stripe/stripe-go/plan" "github.com/stripe/stripe-go/product" + "github.com/stripe/stripe-go/sub" ) -func Service(c Config) ServiceInstance { +func Service(c Config, auth *auth.ServiceInstance) ServiceInstance { stripe.Key = c.StripeKey sc := &client.API{} sc.Init(c.StripeKey, nil) return ServiceInstance{ c: c, stripe: sc, + auth: auth, } } type ServiceInstance struct { c Config stripe *client.API + auth *auth.ServiceInstance } func (si ServiceInstance) Register(uriBase string, s *jch_http.Server) { s.GET(uriBase+"/subscription", "subscription info endpoint", negroni.New( negroni.HandlerFunc(auth.IsAuthenticated), negroni.Wrap(http.HandlerFunc(si.subscriptionHandler)), + )).POST(uriBase+"/subscription", "subscription payment endpoint", negroni.New( + negroni.HandlerFunc(auth.IsAuthenticated), + negroni.Wrap(http.HandlerFunc(si.paymentHandler)), )) + } func (si ServiceInstance) subscriptionHandler(w http.ResponseWriter, r *http.Request) { @@ -54,3 +63,59 @@ type offering struct { Product stripe.Product Plans []stripe.Plan } + +func (si ServiceInstance) paymentHandler(w http.ResponseWriter, r *http.Request) { + + session, err := auth.Store.Get(r, auth.SessionName) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if u, ok := session.Values["profile"]; ok { + user := u.(auth.User) + r.ParseForm() + + params := &stripe.CustomerParams{ + Email: stripe.String(user.Email), + Name: stripe.String(fmt.Sprintf("%s, %s", user.LastName, user.FirstName)), + } + params.SetSource(r.PostFormValue("stripeToken")) + cus, err := customer.New(params) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + p := &stripe.SubscriptionParams{ + Customer: stripe.String(cus.ID), + Items: []*stripe.SubscriptionItemsParams{ + { + Plan: stripe.String(r.PostFormValue("plan")), + }, + }, + } + s, err := sub.New(p) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if si.c.TenantSetup == nil { + panic("need code to setup the tenant") + } + + if user.Apps == nil { + user.Apps = map[string]interface{}{} + } + user.Apps[si.c.StripeProductID] = si.c.TenantSetup(s.ID, user.ID) + err = si.auth.UpdateUser(user) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + http.Redirect(w, r, si.c.RedirectURL, http.StatusSeeOther) + + } +}