forked from wasabee-project/Wasabee-Server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
model_draw_markers.go
319 lines (288 loc) · 8.35 KB
/
model_draw_markers.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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
package wasabee
import (
"database/sql"
"fmt"
"strings"
)
// MarkerID wrapper to ensure type safety
type MarkerID string
// MarkerType will be an enum once we figure out the full list
type MarkerType string
// Marker is defined by the Wasabee IITC plugin.
type Marker struct {
ID MarkerID `json:"ID"`
PortalID PortalID `json:"portalId"`
Type MarkerType `json:"type"`
Comment string `json:"comment"`
AssignedTo GoogleID `json:"assignedTo"`
IngressName string `json:"assignedNickname"`
CompletedBy string `json:"completedBy"`
State string `json:"state"`
Order int `json:"order"`
}
// insertMarkers adds a marker to the database
func (opID OperationID) insertMarker(m Marker) error {
if m.State == "" {
m.State = "pending"
}
_, err := db.Exec("INSERT INTO marker (ID, opID, PortalID, type, gid, comment, state, oporder) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
m.ID, opID, m.PortalID, m.Type, MakeNullString(m.AssignedTo), MakeNullString(m.Comment), m.State, m.Order)
if err != nil {
Log.Error(err)
return err
}
return nil
}
func (opID OperationID) updateMarker(m Marker) error {
if m.State == "" {
m.State = "pending"
}
_, err := db.Exec("INSERT INTO marker (ID, opID, PortalID, type, gid, comment, state, oporder) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE type = ?, PortalID = ?, comment = ?",
m.ID, opID, m.PortalID, m.Type, MakeNullString(m.AssignedTo), MakeNullString(m.Comment), m.State, m.Order, m.Type, m.PortalID, MakeNullString(m.Comment))
if err != nil {
Log.Error(err)
return err
}
return nil
}
func (opID OperationID) deleteMarker(mid MarkerID) error {
_, err := db.Exec("DELETE FROM marker WHERE opID = ? and ID = ?", opID, mid)
if err != nil {
Log.Error(err)
return err
}
return nil
}
// PopulateMarkers fills in the Markers list for the Operation. No authorization takes place.
func (o *Operation) PopulateMarkers() error {
var tmpMarker Marker
var assignedGid, comment, assignedNick, completedBy sql.NullString
// XXX join with portals table, get name and order by name, don't expose it in this json -- will make the friendly in the https module easier
rows, err := db.Query("SELECT m.ID, m.PortalID, m.type, m.gid, m.comment, m.state, a.iname AS assignedTo, b.iname AS completedBy, m.oporder FROM marker=m LEFT JOIN agent=a ON m.gid = a.gid LEFT JOIN agent=b on m.completedby = b.gid WHERE m.opID = ? ORDER BY m.oporder, m.type", o.ID)
if err != nil {
Log.Error(err)
return err
}
defer rows.Close()
for rows.Next() {
err := rows.Scan(&tmpMarker.ID, &tmpMarker.PortalID, &tmpMarker.Type, &assignedGid, &comment, &tmpMarker.State, &assignedNick, &completedBy, &tmpMarker.Order)
if err != nil {
Log.Error(err)
continue
}
if tmpMarker.State == "" { // enums in sql default to "" if invalid, WTF?
tmpMarker.State = "pending"
}
if assignedGid.Valid {
tmpMarker.AssignedTo = GoogleID(assignedGid.String)
} else {
tmpMarker.AssignedTo = ""
}
if assignedNick.Valid {
tmpMarker.IngressName = assignedNick.String
} else {
tmpMarker.IngressName = ""
}
if comment.Valid {
tmpMarker.Comment = comment.String
} else {
tmpMarker.Comment = ""
}
if completedBy.Valid {
tmpMarker.CompletedBy = completedBy.String
} else {
tmpMarker.CompletedBy = ""
}
o.Markers = append(o.Markers, tmpMarker)
}
return nil
}
// String returns the string version of a PortalID
func (m MarkerType) String() string {
return string(m)
}
// String returns the string version of a MarkerID
func (m MarkerID) String() string {
return string(m)
}
// AssignMarker assigns a marker to an agent, sending them a message
func (o *Operation) AssignMarker(markerID MarkerID, gid GoogleID) error {
_, err := db.Exec("UPDATE marker SET gid = ?, state = ? WHERE ID = ? AND opID = ?", MakeNullString(gid), "assigned", markerID, o.ID)
if err != nil {
Log.Error(err)
return err
}
if gid.String() != "" {
o.ID.firebaseAssignMarker(gid, markerID)
marker := struct {
OpID OperationID
MarkerID MarkerID
}{
OpID: o.ID,
MarkerID: markerID,
}
msg, err := gid.ExecuteTemplate("assignMarker", marker)
if err != nil {
Log.Error(err)
msg = fmt.Sprintf("assigned a marker for op %s", o.ID)
// do not report send errors up the chain, just log
}
_, err = gid.SendMessage(msg)
if err != nil {
Log.Errorf("%s %s %s", gid, err, msg)
// do not report send errors up the chain, just log
}
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
return nil
}
// MarkerComment updates the comment on a marker
func (o *Operation) MarkerComment(markerID MarkerID, comment string) error {
_, err := db.Exec("UPDATE marker SET comment = ? WHERE ID = ? AND opID = ?", MakeNullString(comment), markerID, o.ID)
if err != nil {
Log.Error(err)
return err
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
return nil
}
// Acknowledge that a marker has been assigned
// gid must be the assigned agent.
func (m MarkerID) Acknowledge(o *Operation, gid GoogleID) error {
var ns sql.NullString
err := db.QueryRow("SELECT gid FROM marker WHERE ID = ? and opID = ?", m, o.ID).Scan(&ns)
if err != nil && err != sql.ErrNoRows {
Log.Notice(err)
return err
}
if err != nil && err == sql.ErrNoRows {
err = fmt.Errorf("no such marker")
Log.Error(err)
return err
}
if !ns.Valid {
err = fmt.Errorf("marker not assigned")
Log.Error(err)
return err
}
markerGid := GoogleID(ns.String)
if gid != markerGid {
err = fmt.Errorf("marker assigned to someone else")
Log.Error(err)
return err
}
_, err = db.Exec("UPDATE marker SET state = ? WHERE ID = ? AND opID = ?", "acknowledged", m, o.ID)
if err != nil {
Log.Error(err)
return err
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
o.firebaseMarkerStatus(m, "acknowledged")
return nil
}
// Complete marks a marker as completed
func (m MarkerID) Complete(o Operation, gid GoogleID) error {
if !o.ReadAccess(gid) {
err := fmt.Errorf("permission denied")
Log.Error(err)
return err
}
_, err := db.Exec("UPDATE marker SET state = ?, completedby = ? WHERE ID = ? AND opID = ?", "completed", gid, m, o.ID)
if err != nil {
Log.Error(err)
return err
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
o.firebaseMarkerStatus(m, "completed")
return nil
}
// Incomplete marks a marker as not-completed
func (m MarkerID) Incomplete(o Operation, gid GoogleID) error {
if !o.ReadAccess(gid) {
err := fmt.Errorf("permission denied")
Log.Error(err)
return err
}
_, err := db.Exec("UPDATE marker SET state = ?, completedby = NULL WHERE ID = ? AND opID = ?", "assigned", m, o.ID)
if err != nil {
Log.Error(err)
return err
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
o.firebaseMarkerStatus(m, "assigned")
return nil
}
// Reject allows an agent to refuse to take a target
// gid must be the assigned agent.
func (m MarkerID) Reject(o *Operation, gid GoogleID) error {
var ns sql.NullString
err := db.QueryRow("SELECT gid FROM marker WHERE ID = ? and opID = ?", m, o.ID).Scan(&ns)
if err != nil && err != sql.ErrNoRows {
Log.Notice(err)
return err
}
if err != nil && err == sql.ErrNoRows {
err = fmt.Errorf("no such marker")
Log.Error(err)
return err
}
if !ns.Valid {
err = fmt.Errorf("marker not assigned")
Log.Error(err)
return err
}
markerGid := GoogleID(ns.String)
if gid != markerGid {
err = fmt.Errorf("marker assigned to someone else")
Log.Error(err)
return err
}
_, err = db.Exec("UPDATE marker SET state = 'pending', gid = NULL WHERE ID = ? AND opID = ?", m, o.ID)
if err != nil {
Log.Error(err)
return err
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
o.firebaseMarkerStatus(m, "pending")
return nil
}
func (o *Operation) PopulateAssignedOnly(gid GoogleID) error {
// get all marker assignments
return nil
}
// MarkerOrder changes the order of the throws for an operation
func (o *Operation) MarkerOrder(order string, gid GoogleID) error {
stmt, err := db.Prepare("UPDATE marker SET oporder = ? WHERE opID = ? AND ID = ?")
if err != nil {
Log.Error(err)
return err
}
pos := 1
markers := strings.Split(order, ",")
for i := range markers {
if markers[i] == "000" { // the header, could be anyplace in the order if the user was being silly
continue
}
if _, err := stmt.Exec(pos, o.ID, markers[i]); err != nil {
Log.Error(err)
continue
}
pos++
}
if err = o.Touch(); err != nil {
Log.Error(err)
}
return nil
}