-
Notifications
You must be signed in to change notification settings - Fork 20
/
tickets.go
211 lines (180 loc) · 6.05 KB
/
tickets.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package flows
import (
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/gocommon/uuids"
"github.com/nyaruka/goflow/assets"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/utils"
)
// TicketUUID is the UUID of a ticket
type TicketUUID uuids.UUID
// Ticket is a ticket in a ticketing system
type Ticket struct {
uuid TicketUUID
ticketer *Ticketer
subject string
body string
externalID string
assignee *User
}
// NewTicket creates a new ticket
func NewTicket(uuid TicketUUID, ticketer *Ticketer, subject, body, externalID string, assignee *User) *Ticket {
return &Ticket{
uuid: uuid,
ticketer: ticketer,
subject: subject,
body: body,
externalID: externalID,
assignee: assignee,
}
}
// OpenTicket creates a new ticket. Used by ticketing services to open a new ticket.
func OpenTicket(ticketer *Ticketer, subject, body string) *Ticket {
return NewTicket(TicketUUID(uuids.New()), ticketer, subject, body, "", nil)
}
func (t *Ticket) UUID() TicketUUID { return t.uuid }
func (t *Ticket) Ticketer() *Ticketer { return t.ticketer }
func (t *Ticket) Subject() string { return t.subject }
func (t *Ticket) Body() string { return t.body }
func (t *Ticket) ExternalID() string { return t.externalID }
func (t *Ticket) SetExternalID(id string) { t.externalID = id }
func (t *Ticket) Assignee() *User { return t.assignee }
// Context returns the properties available in expressions
//
// uuid:text -> the UUID of the ticket
// subject:text -> the subject of the ticket
// body:text -> the body of the ticket
//
// @context ticket
func (t *Ticket) Context(env envs.Environment) map[string]types.XValue {
return map[string]types.XValue{
"uuid": types.NewXText(string(t.uuid)),
"subject": types.NewXText(t.subject),
"body": types.NewXText(t.body),
"assignee": Context(env, t.assignee),
}
}
//------------------------------------------------------------------------------------------
// JSON Encoding / Decoding
//------------------------------------------------------------------------------------------
type ticketEnvelope struct {
UUID TicketUUID `json:"uuid" validate:"required,uuid4"`
Ticketer *assets.TicketerReference `json:"ticketer" validate:"omitempty,dive"`
Subject string `json:"subject"`
Body string `json:"body"`
ExternalID string `json:"external_id,omitempty"`
Assignee *assets.UserReference `json:"assignee,omitempty" validate:"omitempty,dive"`
}
// ReadTicket decodes a contact from the passed in JSON. If the ticketer or assigned user can't
// be found in the assets, we report the missing asset and return ticket without those.
func ReadTicket(sa SessionAssets, data []byte, missing assets.MissingCallback) (*Ticket, error) {
e := &ticketEnvelope{}
if err := utils.UnmarshalAndValidate(data, e); err != nil {
return nil, err
}
ticketer := sa.Ticketers().Get(e.Ticketer.UUID)
if ticketer == nil {
missing(e.Ticketer, nil)
}
var assignee *User
if e.Assignee != nil {
assignee = sa.Users().Get(e.Assignee.Email)
if assignee == nil {
missing(e.Assignee, nil)
}
}
return &Ticket{
uuid: e.UUID,
ticketer: ticketer,
subject: e.Subject,
body: e.Body,
externalID: e.ExternalID,
assignee: assignee,
}, nil
}
// MarshalJSON marshals this ticket into JSON
func (t *Ticket) MarshalJSON() ([]byte, error) {
var ticketerRef *assets.TicketerReference
if t.ticketer != nil {
ticketerRef = t.ticketer.Reference()
}
var assigneeRef *assets.UserReference
if t.assignee != nil {
assigneeRef = t.assignee.Reference()
}
return jsonx.Marshal(&ticketEnvelope{
UUID: t.uuid,
Ticketer: ticketerRef,
Subject: t.subject,
Body: t.body,
ExternalID: t.externalID,
Assignee: assigneeRef,
})
}
// TicketList defines a contact's list of tickets
type TicketList struct {
tickets []*Ticket
}
// NewTicketList creates a new ticket list
func NewTicketList(tickets []*Ticket) *TicketList {
return &TicketList{tickets: tickets}
}
// returns a clone of this ticket list
func (l *TicketList) clone() *TicketList {
tickets := make([]*Ticket, len(l.tickets))
copy(tickets, l.tickets)
return &TicketList{tickets: tickets}
}
// Adds adds the given ticket to this ticket list
func (l *TicketList) Add(ticket *Ticket) {
l.tickets = append(l.tickets, ticket)
}
// All returns all tickets in this ticket list
func (l *TicketList) All() []*Ticket {
return l.tickets
}
// Count returns the number of tickets
func (l *TicketList) Count() int {
return len(l.tickets)
}
// ToXValue returns a representation of this object for use in expressions
func (l TicketList) ToXValue(env envs.Environment) types.XValue {
array := make([]types.XValue, len(l.tickets))
for i, ticket := range l.tickets {
array[i] = Context(env, ticket)
}
return types.NewXArray(array...)
}
// Ticketer represents a ticket issuing system.
type Ticketer struct {
assets.Ticketer
}
// NewTicketer returns a new classifier object from the given classifier asset
func NewTicketer(asset assets.Ticketer) *Ticketer {
return &Ticketer{Ticketer: asset}
}
// Asset returns the underlying asset
func (t *Ticketer) Asset() assets.Ticketer { return t.Ticketer }
// Reference returns a reference to this classifier
func (t *Ticketer) Reference() *assets.TicketerReference {
return assets.NewTicketerReference(t.UUID(), t.Name())
}
// TicketerAssets provides access to all ticketer assets
type TicketerAssets struct {
byUUID map[assets.TicketerUUID]*Ticketer
}
// NewTicketerAssets creates a new set of ticketer assets
func NewTicketerAssets(ticketers []assets.Ticketer) *TicketerAssets {
s := &TicketerAssets{
byUUID: make(map[assets.TicketerUUID]*Ticketer, len(ticketers)),
}
for _, asset := range ticketers {
s.byUUID[asset.UUID()] = NewTicketer(asset)
}
return s
}
// Get returns the ticketer with the given UUID
func (s *TicketerAssets) Get(uuid assets.TicketerUUID) *Ticketer {
return s.byUUID[uuid]
}