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