@@ -45,13 +45,164 @@ func ApplyRoutes(r *gin.RouterGroup) {
4545 g .POST ("/android" , createSubscriptionAndroid )
4646 g .POST ("/android/webhook" , handleAndroidWebhook )
4747 g .GET ("/offers/:id" , getOffers )
48+ g .POST ("/trial/:id" , createTrial )
4849 g .GET ("/:id" , readSubscription )
4950 g .PATCH ("/:id" , updateSubscription )
5051 g .DELETE ("/:id" , deleteSubscription )
52+ g .DELETE ("/trials" , deleteTrialSubscriptions )
5153 g .GET ("" , readSubscriptions )
5254 }
5355}
5456
57+ func deleteTrialSubscriptions (c * gin.Context ) {
58+
59+ // get the basic auth credentials from the request and check them
60+ // against the environment variables WC_USERNAME and WC_PASSWORD
61+ username , password , ok := c .Request .BasicAuth ()
62+ if ! ok || username != os .Getenv ("WC_USERNAME" ) || password != os .Getenv ("WC_PASSWORD" ) {
63+ log .Error ("deleteTrialSubscriptions: invalid basic auth credentials" )
64+ c .JSON (http .StatusUnauthorized , gin.H {"error" : "Unauthorized" })
65+ return
66+ }
67+
68+ subscriptions , err := core .ReadAllTrials ()
69+ if err != nil {
70+ log .Error (err )
71+ c .JSON (http .StatusInternalServerError , gin.H {"error" : "deleteTrialSubscriptions: Internal server error" })
72+ return
73+ }
74+
75+ now := time .Now ().UTC ()
76+ for _ , subscription := range subscriptions {
77+ if subscription .Status == "active" && subscription .Expires .Before (now ) && ! subscription .Expires .Before (* subscription .Issued ) {
78+ log .Infof ("suspending trial subscription %v" , subscription )
79+ core .ExpireSubscription (subscription .Id )
80+ }
81+ }
82+ c .JSON (http .StatusOK , gin.H {"status" : "OK" , "message" : "Service for expired trial subscriptions suspended" })
83+ }
84+
85+ func createTrial (c * gin.Context ) {
86+ id := c .Param ("id" )
87+
88+ discounts , err := core .GetOffers (id )
89+ if err != nil {
90+ log .Error (err )
91+ c .JSON (http .StatusNotFound , gin.H {"error" : "Offers not found" })
92+ return
93+ }
94+
95+ if len (discounts .Offers ) == 0 {
96+ c .JSON (http .StatusNotFound , gin.H {"error" : "No offers available" })
97+ return
98+ }
99+
100+ // get user from token and add to client infos
101+ oauth2Token := c .MustGet ("oauth2Token" ).(* oauth2.Token )
102+ oauth2Client := c .MustGet ("oauth2Client" ).(model.Authentication )
103+ user , err := oauth2Client .UserInfo (oauth2Token )
104+ if err != nil {
105+ log .WithFields (log.Fields {
106+ "oauth2Token" : oauth2Token ,
107+ "err" : err ,
108+ }).Error ("failed to get user with oauth token" )
109+ c .AbortWithStatus (http .StatusForbidden )
110+ return
111+ }
112+
113+ // update the limits
114+
115+ limits , err := core .ReadLimits (id )
116+ if err != nil {
117+ log .Error (err )
118+ limits_id , err := util .GenerateRandomString (8 )
119+ if err != nil {
120+ log .Error (err )
121+ }
122+ limits_id = "limits-" + limits_id
123+
124+ limits = & model.Limits {
125+ Id : limits_id ,
126+ AccountID : id ,
127+ MaxDevices : 5 ,
128+ MaxNetworks : 2 ,
129+ MaxMembers : 2 ,
130+ MaxServices : 0 ,
131+ Tolerance : core .GetDefaultTolerance (),
132+ CreatedBy : user .Email ,
133+ UpdatedBy : user .Email ,
134+ Created : time .Now (),
135+ Updated : time .Now (),
136+ }
137+ }
138+
139+ limits .MaxDevices += 1
140+ limits .MaxNetworks += 1
141+ limits .MaxServices += 1
142+
143+ errs := limits .IsValid ()
144+ if len (errs ) != 0 {
145+ for _ , err := range errs {
146+ log .WithFields (log.Fields {
147+ "err" : err ,
148+ }).Error ("limits validation error" )
149+ }
150+ c .JSON (http .StatusBadRequest , gin.H {"error" : "Limits validation error" })
151+ return
152+ }
153+
154+ // save limits to mongodb
155+ mongo .Serialize (limits .Id , "id" , "limits" , limits )
156+
157+ // create a new subscription
158+ var subscription model.Subscription
159+ subscription .Id , _ = util .RandomString (8 )
160+ subscription .Id = "trial-" + subscription .Id
161+ subscription .AccountID = user .AccountID
162+ subscription .Email = user .Email
163+ subscription .Name = "Trial"
164+ subscription .Description = "Free 7 Day Trial"
165+ now := time .Now ()
166+ expires := now .AddDate (0 , 0 , 7 )
167+ subscription .Issued = & now
168+ subscription .LastUpdated = & now
169+ subscription .CreatedBy = user .Email
170+ subscription .Expires = & expires
171+ subscription .UpdatedBy = user .Email
172+ subscription .Credits = 1
173+ subscription .Sku = "trial"
174+ subscription .Status = "active"
175+ subscription .AutoRenew = false
176+ subscription .Receipt , _ = util .RandomString (16 ) // generate a random receipt for trial subscriptions
177+ subscription .Receipt = "trial-" + subscription .Receipt
178+ isDeleted := false
179+ subscription .IsDeleted = & isDeleted
180+
181+ errs = subscription .IsValid ()
182+ if len (errs ) != 0 {
183+ for _ , err := range errs {
184+ log .WithFields (log.Fields {
185+ "err" : err ,
186+ }).Error ("subscription validation error" )
187+ }
188+ c .JSON (http .StatusBadRequest , gin.H {"error" : "Subscription validation error" })
189+ return
190+ }
191+
192+ // save subscription to mongodb
193+ mongo .Serialize (subscription .Id , "id" , "subscriptions" , subscription )
194+
195+ log .Infof ("created trial subscription: %s for %s" , subscription .Id , user .Email )
196+
197+ err = core .SubscriptionEmail (& subscription )
198+ if err != nil {
199+ log .Errorf ("failed to send email: %v" , err )
200+ }
201+
202+ c .JSON (http .StatusOK , subscription )
203+
204+ }
205+
55206func getOffers (c * gin.Context ) {
56207 id := c .Param ("id" )
57208 offers , err := core .GetOffers (id )
@@ -303,6 +454,8 @@ func createSubscriptionAndroid(c *gin.Context) {
303454
304455 // construct a subscription object
305456 lu := time .Now ()
457+ isDeleted := false
458+
306459 subscription := model.Subscription {
307460 Id : id ,
308461 AccountID : account .Id ,
@@ -318,6 +471,8 @@ func createSubscriptionAndroid(c *gin.Context) {
318471 Status : "active" ,
319472 AutoRenew : autoRenew ,
320473 Receipt : receipt .Receipt ,
474+ IsDeleted : & isDeleted ,
475+ CreatedBy : receipt .Email ,
321476 }
322477
323478 errs = subscription .IsValid ()
@@ -592,18 +747,16 @@ func handleAndroidWebhook(c *gin.Context) {
592747 } else {
593748 last := time .Now ().UTC ()
594749 subscription .LastUpdated = & last
595- subscription .UpdatedBy = "google"
596- core .UpdateSubscription (subscription .Id , subscription )
597750 log .Infof ("subscription updated: %s %v" , subscription .Id , subscription )
598751 // c.JSON(http.StatusOK, gin.H{"status": "updated"})
599752 // return
600753 }
754+ subscription .UpdatedBy = "google"
755+ core .UpdateSubscription (subscription .Id , subscription )
601756 }
602757
603758 if sub ["subscriptionState" ] != nil && sub ["subscriptionState" ].(string ) == "SUBSCRIPTION_STATE_EXPIRED" {
604759
605- subscription .Status = "expired"
606-
607760 core .ExpireSubscription (subscription .Id )
608761
609762 log .Infof ("subscription expired: %s" , subscription .Id )
@@ -618,6 +771,7 @@ func handleAndroidWebhook(c *gin.Context) {
618771
619772 subscription .Status = "cancelled"
620773 core .UpdateSubscription (subscription .Id , subscription )
774+ core .ExpireSubscription (subscription .Id )
621775 core .SubscriptionEmail (subscription )
622776
623777 log .Infof ("subscription cancelled: %s" , subscription .Id )
@@ -816,13 +970,14 @@ func handleAppleWebhook(c *gin.Context) {
816970 log .Infof ("apple: subscription RENWAL: %s until %s" , subscription .Id , expires )
817971
818972 case "CANCEL" :
819- subscription .Status = "cancelled "
973+ subscription .Status = "active "
820974 core .UpdateSubscription (subscription .Id , subscription )
975+
976+ // this will only expire services if it is after the expires date
977+ core .ExpireSubscription (subscription .Id )
821978 log .Infof ("apple: subscription CANCEL: %s" , subscription .Id )
822979
823980 case "DID_NOT_RENEW" :
824- subscription .Status = "expired"
825- core .UpdateSubscription (subscription .Id , subscription )
826981 core .ExpireSubscription (subscription .Id )
827982 log .Infof ("apple: subscription DID_NOT_RENEW: %s at %s" , subscription .Id , expires )
828983 }
@@ -911,7 +1066,7 @@ func handleAppleDiscount(c *gin.Context) {
9111066}
9121067
9131068func fetchApplePublicKey (kid string ) (* rsa.PublicKey , error ) {
914- resp , err := http .Get ("https://appleid .apple.com/auth/keys" )
1069+ resp , err := http .Get ("https://account .apple.com/auth/keys" )
9151070 if err != nil {
9161071 return nil , err
9171072 }
@@ -1280,6 +1435,7 @@ func createSubscriptionApple(c *gin.Context) {
12801435
12811436 // construct a subscription object
12821437 lu := time .Now ()
1438+ isDeleted := false
12831439 subscription := model.Subscription {
12841440 Id : id ,
12851441 AccountID : account .Id ,
@@ -1295,6 +1451,7 @@ func createSubscriptionApple(c *gin.Context) {
12951451 Status : "active" ,
12961452 AutoRenew : autoRenew ,
12971453 Receipt : receipt .Receipt ,
1454+ IsDeleted : & isDeleted ,
12981455 }
12991456
13001457 errs = subscription .IsValid ()
@@ -1316,7 +1473,6 @@ func createSubscriptionApple(c *gin.Context) {
13161473 }
13171474
13181475 c .JSON (http .StatusOK , subscription )
1319- return
13201476
13211477}
13221478
@@ -1751,6 +1907,7 @@ func createHelioSubscription(c *gin.Context) {
17511907 issued := time .Now ()
17521908 lu := time .Now ()
17531909 expires := endedAtUnix
1910+ isDeleted := false
17541911 subscription := model.Subscription {
17551912 Id : id ,
17561913 AccountID : account .Id ,
@@ -1763,6 +1920,9 @@ func createHelioSubscription(c *gin.Context) {
17631920 Credits : credits ,
17641921 Sku : sku ,
17651922 Status : status ,
1923+ IsDeleted : & isDeleted ,
1924+ UpdatedBy : email ,
1925+ CreatedBy : email ,
17661926 }
17671927
17681928 errs = subscription .IsValid ()
@@ -2081,6 +2241,7 @@ func createSubscription(c *gin.Context) {
20812241 // construct a subscription object
20822242 issued := time .Now ()
20832243 lu := time .Now ()
2244+ isDeleted := false
20842245 subscription := model.Subscription {
20852246 Id : id ,
20862247 AccountID : account .Id ,
@@ -2094,6 +2255,9 @@ func createSubscription(c *gin.Context) {
20942255 Sku : sku ,
20952256 Status : status ,
20962257 Receipt : receipt ,
2258+ IsDeleted : & isDeleted ,
2259+ UpdatedBy : email ,
2260+ CreatedBy : email ,
20972261 }
20982262
20992263 errs = subscription .IsValid ()
0 commit comments