|
1 | 1 | package main |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "database/sql" |
4 | 5 | "encoding/json" |
5 | 6 | "fmt" |
6 | 7 | "log/slog" |
@@ -62,44 +63,55 @@ func (s session) respond(st Status, msg string, data H) { |
62 | 63 | } |
63 | 64 |
|
64 | 65 | func (s session) handle() { |
65 | | - var cmds = s.Command() |
66 | | - if len(cmds) == 0 { |
| 66 | + var parts = s.Command() |
| 67 | + if len(parts) == 0 { |
67 | 68 | s.respond(StatusError, "no command specified", nil) |
68 | 69 | return |
69 | 70 | } |
70 | 71 |
|
71 | | - var command = cmds[0] |
| 72 | + var command, args = parts[0], parts[1:] |
72 | 73 | switch command { |
73 | 74 | case "version": |
74 | 75 | s.respond(StatusSuccess, "", H{"version": version.Version}) |
75 | 76 |
|
76 | 77 | case "job-status": |
77 | | - if len(cmds) != 2 { |
| 78 | + if len(args) != 1 { |
78 | 79 | s.respond(StatusError, "You must supply a job ID", nil) |
79 | 80 | return |
80 | 81 | } |
81 | | - s.getJobStatus(cmds[1]) |
| 82 | + s.getJobStatus(args[0]) |
82 | 83 |
|
83 | 84 | case "job-logs": |
84 | | - if len(cmds) != 2 { |
| 85 | + if len(args) != 1 { |
85 | 86 | s.respond(StatusError, "You must supply a job ID", nil) |
86 | 87 | return |
87 | 88 | } |
88 | | - s.getJobLogs(cmds[1]) |
| 89 | + s.getJobLogs(args[0]) |
89 | 90 |
|
90 | 91 | case "load-batch": |
91 | | - if len(cmds) != 2 { |
| 92 | + if len(args) != 1 { |
92 | 93 | s.respond(StatusError, fmt.Sprintf("%q requires exactly one batch name", command), nil) |
93 | 94 | return |
94 | 95 | } |
95 | | - s.loadBatch(cmds[1]) |
| 96 | + s.loadBatch(args[0]) |
96 | 97 |
|
97 | 98 | case "purge-batch": |
98 | | - if len(cmds) != 2 { |
| 99 | + if len(args) != 1 { |
99 | 100 | s.respond(StatusError, fmt.Sprintf("%q requires exactly one batch name", command), nil) |
100 | 101 | return |
101 | 102 | } |
102 | | - s.purgeBatch(cmds[1]) |
| 103 | + s.purgeBatch(args[0]) |
| 104 | + |
| 105 | + case "ensure-awardee": |
| 106 | + if len(args) < 1 || len(args) > 2 { |
| 107 | + s.respond(StatusError, fmt.Sprintf("%q requires one or two args: MARC org code and awardee name. Name is required if the awardee is to be auto-created.", command), nil) |
| 108 | + return |
| 109 | + } |
| 110 | + |
| 111 | + if len(args) == 1 { |
| 112 | + args = []string{args[0], ""} |
| 113 | + } |
| 114 | + s.ensureAwardee(args[0], args[1]) |
103 | 115 |
|
104 | 116 | default: |
105 | 117 | s.respond(StatusError, fmt.Sprintf("%q is not a valid command name", command), nil) |
@@ -185,6 +197,62 @@ func (s session) queueJob(command string, args ...string) { |
185 | 197 | s.respond(StatusSuccess, "Job added to queue", H{"job": H{"id": id}}) |
186 | 198 | } |
187 | 199 |
|
| 200 | +func (s session) ensureAwardee(code string, name string) { |
| 201 | + var rows, err = dbPool.Query("SELECT COUNT(*) FROM core_awardee WHERE org_code = ?", code) |
| 202 | + if err != nil { |
| 203 | + s.respond(StatusError, "Unable to query database", H{"error": err.Error()}) |
| 204 | + return |
| 205 | + } |
| 206 | + defer rows.Close() |
| 207 | + |
| 208 | + // What does it mean if there's no error reported, but no count returned? |
| 209 | + if !rows.Next() { |
| 210 | + s.respond(StatusError, "Unable to count awardees in database", H{"error": "no rows returned by SQL COUNT()"}) |
| 211 | + return |
| 212 | + } |
| 213 | + |
| 214 | + var count int |
| 215 | + err = rows.Scan(&count) |
| 216 | + if err != nil { |
| 217 | + s.respond(StatusError, "Unable to count awardees in database", H{"error": err.Error()}) |
| 218 | + return |
| 219 | + } |
| 220 | + |
| 221 | + // We really only care that there's at least one row. If there are dupes, |
| 222 | + // that's out of scope to deal with, and technically not an error in terms of |
| 223 | + // what we need. |
| 224 | + if count > 0 { |
| 225 | + s.respond(StatusSuccess, "Awardee already exists", nil) |
| 226 | + return |
| 227 | + } |
| 228 | + |
| 229 | + // No rows, no error: if a name was given, create the awardee, otherwise abort |
| 230 | + if name == "" { |
| 231 | + s.respond(StatusError, "Unable to create awardee", H{"error": "awardee name must be given to auto-create awardees", "org_code": code, "name": name}) |
| 232 | + return |
| 233 | + } |
| 234 | + |
| 235 | + var result sql.Result |
| 236 | + result, err = dbPool.Exec("INSERT INTO core_awardee (`org_code`, `name`, `created`) VALUES(?, ?, NOW())", code, name) |
| 237 | + if err != nil { |
| 238 | + s.respond(StatusError, "Unable to create awardee", H{"error": err.Error(), "org_code": code, "name": name}) |
| 239 | + return |
| 240 | + } |
| 241 | + var n int64 |
| 242 | + n, err = result.RowsAffected() |
| 243 | + if err != nil { |
| 244 | + s.respond(StatusError, "Unable to read result of INSERT", H{"error": err.Error(), "org_code": code, "name": name}) |
| 245 | + return |
| 246 | + } |
| 247 | + if n != 1 { |
| 248 | + s.respond(StatusError, "Unable to create awardee", H{"error": "No rows created", "org_code": code, "name": name}) |
| 249 | + return |
| 250 | + } |
| 251 | + |
| 252 | + s.respond(StatusSuccess, "Awardee created", nil) |
| 253 | + return |
| 254 | +} |
| 255 | + |
188 | 256 | // close terminates the session, always with a status of 0: Go ssh clients |
189 | 257 | // return an error if the request is anything but successful, so the caller has |
190 | 258 | // to parse the status instead. |
|
0 commit comments