ducky/subscriptions

Paddy 2015-07-18 Parent:b240b6123548 Child:fb2c0e498e37

9:8eb19bcbf17d Go to Latest

ducky/subscriptions/subscription_memstore.go

Return errors from responses in client. When the client makes a request, non-200 responses _are not_ considered errors. So we need to check the response.Errors property, and if it has errors, _then_ we consider the request to have an error. To make this happen, we created an httpErrors type that fulfills the error interface and just wraps the response Errors property. Then callers can type-cast it and interrogate it.

History
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@3 16 func (m *Memstore) CreateSubscription(sub Subscription) error {
paddy@0 17 m.subscriptionLock.Lock()
paddy@0 18 defer m.subscriptionLock.Unlock()
paddy@0 19
paddy@1 20 if _, ok := m.subscriptions[sub.UserID.String()]; ok {
paddy@0 21 return ErrSubscriptionAlreadyExists
paddy@0 22 }
paddy@2 23 if stripeSubscriptionInMemstore(sub.StripeSubscription, m) {
paddy@2 24 return ErrStripeSubscriptionAlreadyExists
paddy@0 25 }
paddy@1 26 m.subscriptions[sub.UserID.String()] = sub
paddy@0 27 return nil
paddy@0 28 }
paddy@0 29
paddy@3 30 func (m *Memstore) UpdateSubscription(id uuid.ID, change SubscriptionChange) error {
paddy@0 31 if change.IsEmpty() {
paddy@0 32 return ErrSubscriptionChangeEmpty
paddy@0 33 }
paddy@0 34
paddy@0 35 m.subscriptionLock.Lock()
paddy@0 36 defer m.subscriptionLock.Unlock()
paddy@0 37
paddy@0 38 s, ok := m.subscriptions[id.String()]
paddy@0 39 if !ok {
paddy@0 40 return ErrSubscriptionNotFound
paddy@0 41 }
paddy@2 42 if change.StripeSubscription != nil {
paddy@2 43 if stripeSubscriptionInMemstore(*change.StripeSubscription, m) {
paddy@2 44 return ErrStripeSubscriptionAlreadyExists
paddy@0 45 }
paddy@0 46 }
paddy@0 47 s.ApplyChange(change)
paddy@0 48 m.subscriptions[id.String()] = s
paddy@0 49 return nil
paddy@0 50 }
paddy@0 51
paddy@3 52 func (m *Memstore) DeleteSubscription(id uuid.ID) error {
paddy@0 53 m.subscriptionLock.Lock()
paddy@0 54 defer m.subscriptionLock.Unlock()
paddy@0 55
paddy@0 56 _, ok := m.subscriptions[id.String()]
paddy@0 57 if !ok {
paddy@0 58 return ErrSubscriptionNotFound
paddy@0 59 }
paddy@0 60 delete(m.subscriptions, id.String())
paddy@0 61 return nil
paddy@0 62 }
paddy@0 63
paddy@3 64 func (m *Memstore) GetSubscriptions(ids []uuid.ID) (map[string]Subscription, error) {
paddy@0 65 if len(ids) < 1 {
paddy@0 66 return map[string]Subscription{}, ErrNoSubscriptionID
paddy@0 67 }
paddy@0 68 m.subscriptionLock.RLock()
paddy@0 69 defer m.subscriptionLock.RUnlock()
paddy@0 70
paddy@0 71 result := map[string]Subscription{}
paddy@0 72
paddy@0 73 for _, id := range ids {
paddy@0 74 s, ok := m.subscriptions[id.String()]
paddy@0 75 if !ok {
paddy@0 76 continue
paddy@0 77 }
paddy@1 78 result[s.UserID.String()] = s
paddy@0 79 }
paddy@0 80 return result, nil
paddy@0 81 }
paddy@0 82
paddy@3 83 func (m *Memstore) GetSubscriptionStats() (SubscriptionStats, error) {
paddy@0 84 m.subscriptionLock.RLock()
paddy@0 85 defer m.subscriptionLock.RUnlock()
paddy@0 86
paddy@2 87 stats := SubscriptionStats{
paddy@2 88 Plans: map[string]int64{},
paddy@2 89 }
paddy@1 90
paddy@0 91 for _, subscription := range m.subscriptions {
paddy@1 92 stats.Number++
paddy@2 93 stats.Plans[subscription.Plan]++
paddy@0 94
paddy@2 95 if subscription.Canceling {
paddy@2 96 stats.Canceling++
paddy@2 97 }
paddy@2 98 if subscription.Status == "past_due" || subscription.Status == "unpaid" {
paddy@2 99 stats.Failing++
paddy@2 100 }
paddy@1 101 }
paddy@1 102 return stats, nil
paddy@0 103 }