-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapi.go
More file actions
195 lines (173 loc) · 5.17 KB
/
api.go
File metadata and controls
195 lines (173 loc) · 5.17 KB
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
package main
import (
"database/sql"
"fmt"
"log"
"slices"
"strings"
"time"
)
// BTRData struct to hold the results of the MySQL query
type BTRData struct {
Btr string `json:"btr"`
Beamline string `json:"beamline"`
PI string `json:"pi"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
}
// getBTR performs the MySQL query and returns the results
func getBTR(btrs []string, beamline, startTime, endTime, dateTime string) ([]BTRData, error) {
var err error
var rows *sql.Rows
// Common to all queries, no matter the user parameters
baseQuery := `
SELECT
br.schedule_entry_file_id AS btr,
r.name AS beamline,
pn.last_name,
se.start_datetime,
se.end_datetime
FROM beampass.resource r
JOIN beampass.schedule_entry se ON se.resource_id = r.id
JOIN beampass.beamtime_request br ON se.beamtime_request_id = br.id
JOIN beampass.project p ON br.project_id = p.id
JOIN beampass.affiliation a ON p.lead_id = a.id
JOIN beampass.person pn ON a.person_id = pn.id
`
var whereClauses []string
var queryArgs []any
whereClauses = append(whereClauses, "se.is_actual = true")
if beamline != "" {
whereClauses = append(whereClauses, "r.name = ?")
queryArgs = append(queryArgs, beamline)
}
if btrs != nil {
whereClauses = append(whereClauses, "br.schedule_entry_file_id IN ("+strings.Join(slices.Repeat([]string{"?"}, len(btrs)), ",")+")")
for _, btr := range btrs {
queryArgs = append(queryArgs, btr)
}
}
if dateTime != "" {
whereClauses = append(whereClauses, "se.start_datetime < ? AND se.end_datetime > ?")
queryArgs = append(queryArgs, dateTime, dateTime)
} else {
if startTime != "" {
whereClauses = append(whereClauses, "se.start_datetime >= ?")
queryArgs = append(queryArgs, startTime)
}
if endTime != "" {
whereClauses = append(whereClauses, "se.end_datetime <= ?")
queryArgs = append(queryArgs, endTime)
}
}
query := baseQuery
if len(whereClauses) > 0 {
query += " WHERE " + strings.Join(whereClauses, " AND ")
}
query += " ORDER BY se.start_datetime;"
if _verbose > 0 {
log.Printf("QUERY: %s, queryArgs=%v", query, queryArgs)
}
rows, err = db.Query(query, queryArgs...)
if err != nil {
return nil, fmt.Errorf("error executing query: %w", err)
}
defer rows.Close()
var results []BTRData
for rows.Next() {
var data BTRData
if err := rows.Scan(&data.Btr, &data.Beamline, &data.PI, &data.StartTime, &data.EndTime); err != nil {
return nil, fmt.Errorf("error scanning row: %w", err)
}
results = append(results, data)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("error during rows iteration: %w", err)
}
return results, nil
}
func parseDate(s string) (string, error) {
const layout = "2006-01-02 15:04:05"
var err error
if s == "" {
return s, nil
}
var tstmp time.Time
if len(s) == 8 {
// Format: YYYYMMDD
tstmp, err = time.ParseInLocation("20060102", s, time.Local)
} else if len(s) == 10 {
// Format: YYYY-MM-DD
tstmp, err = time.ParseInLocation("2006-01-02", s, time.Local)
} else {
tstmp, err = time.ParseInLocation("2006-01-02 15:04:05", s, time.Local)
}
if err != nil {
return "", fmt.Errorf("[BeamPass.main.parseDate] time.ParseInLocation error: %w", err)
}
return tstmp.Format(layout), nil
}
// UserInfo represents user info in BeamPass database
type UserInfo struct {
UID string `json:"uid"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Affiliation string `json:"affiliation"`
OrchidId *string `json:"orchid_id"`
Organization *string `json:"organization"`
City *string `json:"city"`
State *string `json:"state"`
Zip *string `json:"zip"`
Country *string `json:"country"`
Department *string `json:"department"`
}
func getAffiliations(uids []string) []UserInfo {
var err error
var rows *sql.Rows
var results []UserInfo
query := `
SELECT DISTINCT
p.classe_id, p.first_name, p.last_name,
p.email, p.orcid_id, o.name as organization,
p.city, r.name as state, p.zip,
c.code3 as country,
a.department
FROM person p
JOIN affiliation a
ON p.id = a.person_id
JOIN country c
ON p.country_id = c.id
JOIN region r
ON r.country_id = c.id
JOIN organization o
ON a.organization_id = o.id
WHERE a.archived_datetime IS NULL
AND r.id = p.region_id
AND r.name IS NOT NULL
AND r.name <> ''
`
var queryArgs []any
for _, uid := range uids {
queryArgs = append(queryArgs, uid)
}
query += " AND p.classe_id IN (" + strings.Join(slices.Repeat([]string{"?"}, len(uids)), ",") + ")" + "LIMIT 1"
rows, err = db.Query(query, queryArgs...)
if err != nil {
log.Printf("ERROR: executing query: %v", err)
return results
}
defer rows.Close()
for rows.Next() {
var data UserInfo
if err := rows.Scan(&data.UID,
&data.FirstName, &data.LastName, &data.Email, &data.OrchidId,
&data.Organization, &data.City, &data.State, &data.Zip, &data.Country,
&data.Department); err != nil {
log.Printf("ERROR: scanning row: %v", err)
}
data.Affiliation = composeAffiliation(data)
results = append(results, data)
}
return results
}