ducky/subscriptions

Paddy 2015-09-30 Parent:b240b6123548

14:fb2c0e498e37 Go to Latest

ducky/subscriptions/subscription_memstore.go

Update with comments for all exported functions. We now have golint-approved comments for all the exported functions in the subscriptions package. Next challenge: all the sub-packages!

History
1 package subscriptions
3 import (
4 "code.secondbit.org/uuid.hg"
5 )
7 func stripeSubscriptionInMemstore(stripeSubscription string, m *Memstore) bool {
8 for _, sub := range m.subscriptions {
9 if sub.StripeSubscription == stripeSubscription {
10 return true
11 }
12 }
13 return false
14 }
16 // CreateSubscription stores the passed Subscription in the Memstore. If
17 // a Subscription sharing the same UserID already exists, an
18 // ErrSubscriptionAlreadyExists error will be returned. If a Subscription
19 // sharing the same StripeSubscription already exists, an
20 // ErrStripeSubscriptionAlreadyExists error will be returned.
21 func (m *Memstore) CreateSubscription(sub Subscription) error {
22 m.subscriptionLock.Lock()
23 defer m.subscriptionLock.Unlock()
25 if _, ok := m.subscriptions[sub.UserID.String()]; ok {
26 return ErrSubscriptionAlreadyExists
27 }
28 if stripeSubscriptionInMemstore(sub.StripeSubscription, m) {
29 return ErrStripeSubscriptionAlreadyExists
30 }
31 m.subscriptions[sub.UserID.String()] = sub
32 return nil
33 }
35 // UpdateSubscription applies the SubscriptionChange passed to the Subscription
36 // stored in the Memstore associated with the passed ID. If change is empty,
37 // an ErrSubscriptionChangeEmpty error is returned. If no Subscription is found
38 // in the Memstore with the passed ID, an ErrSubscriptionNotFound error is returned.
39 // If change is updating the StripeSubscription, and a Subscription in the Memstore
40 // already has that value set for StripeSubscription, an
41 // ErrStripeSubscriptionAlreadyExists error is returned.
42 func (m *Memstore) UpdateSubscription(id uuid.ID, change SubscriptionChange) error {
43 if change.IsEmpty() {
44 return ErrSubscriptionChangeEmpty
45 }
47 m.subscriptionLock.Lock()
48 defer m.subscriptionLock.Unlock()
50 s, ok := m.subscriptions[id.String()]
51 if !ok {
52 return ErrSubscriptionNotFound
53 }
54 if change.StripeSubscription != nil {
55 if stripeSubscriptionInMemstore(*change.StripeSubscription, m) {
56 return ErrStripeSubscriptionAlreadyExists
57 }
58 }
59 s.ApplyChange(change)
60 m.subscriptions[id.String()] = s
61 return nil
62 }
64 // DeleteSubscription removes the Subscription stored in the Memstore associated
65 // with the passed ID from the Memstore. If no Subscription is found
66 // in the Memstore with the passed ID, an ErrSubscriptionNotFound error is returned.
67 func (m *Memstore) DeleteSubscription(id uuid.ID) error {
68 m.subscriptionLock.Lock()
69 defer m.subscriptionLock.Unlock()
71 _, ok := m.subscriptions[id.String()]
72 if !ok {
73 return ErrSubscriptionNotFound
74 }
75 delete(m.subscriptions, id.String())
76 return nil
77 }
79 // GetSubscriptions retrieves the Subscriptions stored in the Memstore associated
80 // with the passed IDs. If no IDs are passed, an ErrNoSubscriptionID error is
81 // returned. No matter how many of the IDs are found (including none), a map is
82 // returned, with the key being a String()ed version of the ID for the Subscription in
83 // the value. If no error is returned, the map will represent all of the Subscriptions// matching the passed IDs that exist in the Memstore, even if it's empty.
84 func (m *Memstore) GetSubscriptions(ids []uuid.ID) (map[string]Subscription, error) {
85 if len(ids) < 1 {
86 return map[string]Subscription{}, ErrNoSubscriptionID
87 }
88 m.subscriptionLock.RLock()
89 defer m.subscriptionLock.RUnlock()
91 result := map[string]Subscription{}
93 for _, id := range ids {
94 s, ok := m.subscriptions[id.String()]
95 if !ok {
96 continue
97 }
98 result[s.UserID.String()] = s
99 }
100 return result, nil
101 }
103 // GetSubscriptionStats returns statistics about the subscription data stored in the
104 // Memstore as a SubscriptionStats variable. The number of Subscriptions, the
105 // breakdown of how many Subscriptions belong to each plan, the number of
106 // Subscriptions that are canceling, and the number of Subscriptions whose payment
107 // information is failing are all tracked.
108 func (m *Memstore) GetSubscriptionStats() (SubscriptionStats, error) {
109 m.subscriptionLock.RLock()
110 defer m.subscriptionLock.RUnlock()
112 stats := SubscriptionStats{
113 Plans: map[string]int64{},
114 }
116 for _, subscription := range m.subscriptions {
117 stats.Number++
118 stats.Plans[subscription.Plan]++
120 if subscription.Canceling {
121 stats.Canceling++
122 }
123 if subscription.Status == "past_due" || subscription.Status == "unpaid" {
124 stats.Failing++
125 }
126 }
127 return stats, nil
128 }