ducky/subscriptions

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

7:9e138933e4ce Go to Latest

ducky/subscriptions/subscription_memstore.go

Create a client for working with subscriptions. We mostly copied our code.secondbit.org/auth.hg/client package to create a simple client library for communicating with our Subscriptions API. Right now, the client only has support for creating a subscription. It remains untested, but it builds.

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 }