forked from benbjohnson/wtf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
es_dial.go
148 lines (128 loc) · 4.17 KB
/
es_dial.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package wtf
import (
"errors"
"fmt"
"strconv"
"time"
"github.com/hallgren/eventsourcing"
)
// ESDial represents an aggregate WTF level. They are used to roll up the WTF
// levels of multiple members and show an average WTF level.
//
// A dial is created by a user and can only be edited & deleted by the user who
// created it. Members can be added by sharing an invite link and accepting the
// invitation.
//
// The WTF level for the dial will immediately change when a member's WTF level
// changes and the change will be announced to all other members in real-time.
//
// See the EventService for more information about notifications.
type ESDial struct {
// include the eventsourcing.AggregateRoot to enable to handle events to state translate the dial entity
eventsourcing.AggregateRoot
ID int `json:"id"`
// Owner of the dial. Only the owner may delete the dial.
UserID int `json:"userID"`
User *User `json:"user"`
// Human-readable name of the dial.
Name string `json:"name"`
// Code used to share the dial with other users.
// It allows the creation of a shareable link without explicitly inviting users.
InviteCode string `json:"inviteCode,omitempty"`
// Aggregate WTF level for the dial. This is a computed field based on the
// average value of each member's WTF level.
Value int `json:"value"`
// Timestamps for dial creation & last update.
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
// List of associated members and their contributing WTF level.
// This is only set when returning a single dial.
Memberships []*DialMembership `json:"memberships,omitempty"`
}
// Created event happends when the dial is first created
type Created struct {
OwnerID int
Name string
InviteCode string
}
// SelfMembershipCreated event is attached when the dial is created
type SelfMembershipCreated struct {
ID int
Value int
}
// MembershipCreated event when a user is adding a dial membership
type MembershipCreated struct {
ID int
UserID int
Value int
}
// Transition builds the dial entity from its events
func (d *ESDial) Transition(event eventsourcing.Event) {
switch e := event.Data.(type) {
case *Created:
i, _ := strconv.Atoi(event.AggregateRootID)
d.ID = i
d.Name = e.Name
d.CreatedAt = event.Timestamp
d.UserID = e.OwnerID
d.InviteCode = e.InviteCode
d.Memberships = make([]*DialMembership, 0)
d.UpdatedAt = event.Timestamp
case *SelfMembershipCreated:
membership := DialMembership{
ID: e.ID,
Value: e.Value,
UserID: d.UserID,
}
d.Memberships = append(d.Memberships, &membership)
d.UpdatedAt = event.Timestamp
case *MembershipCreated:
membership := DialMembership{
ID: e.ID,
Value: e.Value,
UserID: e.UserID,
CreatedAt: event.Timestamp,
UpdatedAt: event.Timestamp,
}
d.Memberships = append(d.Memberships, &membership)
d.UpdatedAt = event.Timestamp
}
// calculate the dial value from the Memberships after the dial entity is built from all events
// this is calculated on every event but the final event will be the final result of the Value on the dial
if len(d.Memberships) > 0 {
value := 0
for _, m := range d.Memberships {
value += m.Value
}
d.Value = value / len(d.Memberships)
}
}
func NewDial(userID, value int, name string) (*ESDial, error) {
if name == "" {
return nil, errors.New("name can't be empty")
}
dial := ESDial{}
dial.TrackChange(&dial, &Created{OwnerID: userID, Name: name, InviteCode: "123"})
dial.TrackChange(&dial, &SelfMembershipCreated{ID: 1, Value: value})
return &dial, nil
}
func (d *ESDial) AddMembership(userID int, value int) error {
for _, membership := range d.Memberships {
fmt.Println(membership.UserID, userID)
if membership.UserID == userID {
return fmt.Errorf("user membership already exist")
}
}
d.TrackChange(d, &MembershipCreated{UserID: userID, Value: value})
return nil
}
// MembershipByUserID returns the membership attached to the dial for a given user.
// Returns nil if user is not associated with the dial or if memberships is unset.
func (d *ESDial) MembershipByUserID(userID int) *DialMembership {
for _, m := range d.Memberships {
if m.UserID == userID {
return m
}
}
return nil
}