Skip to content

Commit 855610c

Browse files
committed
fix apple id, refresh_token, subscriptions
1 parent 230d6c6 commit 855610c

File tree

9 files changed

+557
-98
lines changed

9 files changed

+557
-98
lines changed

api/v1/subscription/subscription.go

Lines changed: 173 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
55206
func 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

9131068
func 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

Comments
 (0)