1
- use crate :: types:: api:: ApiError ;
2
- use crate :: types:: models:: developer:: FetchedDeveloper ;
3
- use sqlx:: PgConnection ;
1
+ use crate :: types:: api:: { ApiError , PaginatedData } ;
2
+ use crate :: types:: models:: developer:: { ModDeveloper , Developer } ;
3
+ use futures:: TryFutureExt ;
4
+ use sqlx:: { PgConnection , Postgres , QueryBuilder } ;
5
+ use std:: collections:: hash_map:: Entry ;
6
+ use std:: collections:: HashMap ;
7
+
8
+ pub async fn index (
9
+ query : Option < & String > ,
10
+ page : i64 ,
11
+ per_page : i64 ,
12
+ conn : & mut PgConnection ,
13
+ ) -> Result < PaginatedData < Developer > , ApiError > {
14
+ let limit = per_page;
15
+ let offset = ( page - 1 ) * per_page;
16
+
17
+ let display_name_query = query. map ( |str| format ! ( "%{}%" , str ) ) ;
18
+
19
+ let result = sqlx:: query_as!(
20
+ Developer ,
21
+ "SELECT
22
+ id,
23
+ username,
24
+ display_name,
25
+ verified,
26
+ admin
27
+ FROM developers
28
+ WHERE (
29
+ ($1 = '' OR username = $1)
30
+ OR ($2 = '' OR display_name ILIKE $2)
31
+ )
32
+ GROUP BY id
33
+ LIMIT $3
34
+ OFFSET $4" ,
35
+ query,
36
+ display_name_query,
37
+ limit,
38
+ offset
39
+ )
40
+ . fetch_all ( & mut * conn)
41
+ . await
42
+ . map_err ( |e| {
43
+ log:: error!( "Failed to fetch developers: {}" , e) ;
44
+ ApiError :: DbError
45
+ } ) ?;
46
+
47
+ let count = index_count ( query, & mut * conn) . await ?;
48
+
49
+ Ok ( PaginatedData {
50
+ data : result,
51
+ count,
52
+ } )
53
+ }
54
+
55
+ pub async fn index_count ( query : Option < & String > , conn : & mut PgConnection ) -> Result < i64 , ApiError > {
56
+ let display_name_query = query. map ( |str| format ! ( "%{}%" , str ) ) ;
57
+
58
+ Ok ( sqlx:: query!(
59
+ "SELECT COUNT(id)
60
+ FROM developers
61
+ WHERE (
62
+ ($1 = '' OR username = $1)
63
+ OR ($2 = '' OR display_name ILIKE $2)
64
+ )" ,
65
+ query,
66
+ display_name_query
67
+ )
68
+ . fetch_one ( & mut * conn)
69
+ . await
70
+ . map_err ( |e| {
71
+ log:: error!( "Failed to fetch developer count: {}" , e) ;
72
+ ApiError :: DbError
73
+ } ) ?
74
+ . count
75
+ . unwrap_or ( 0 ) )
76
+ }
4
77
5
78
pub async fn fetch_or_insert_github (
6
79
github_id : i64 ,
7
80
username : & str ,
8
81
conn : & mut PgConnection ,
9
- ) -> Result < FetchedDeveloper , ApiError > {
82
+ ) -> Result < Developer , ApiError > {
10
83
match sqlx:: query_as!(
11
- FetchedDeveloper ,
84
+ Developer ,
12
85
"SELECT
13
86
id,
14
87
username,
@@ -34,9 +107,9 @@ async fn insert_github(
34
107
github_id : i64 ,
35
108
username : & str ,
36
109
conn : & mut PgConnection ,
37
- ) -> Result < FetchedDeveloper , ApiError > {
110
+ ) -> Result < Developer , ApiError > {
38
111
Ok ( sqlx:: query_as!(
39
- FetchedDeveloper ,
112
+ Developer ,
40
113
"INSERT INTO developers(username, display_name, github_user_id)
41
114
VALUES ($1, $1, $2)
42
115
RETURNING
@@ -56,12 +129,189 @@ async fn insert_github(
56
129
} ) ?)
57
130
}
58
131
132
+ pub async fn get_one (
133
+ id : i32 ,
134
+ conn : & mut PgConnection ,
135
+ ) -> Result < Option < Developer > , ApiError > {
136
+ Ok ( sqlx:: query_as!(
137
+ Developer ,
138
+ "SELECT
139
+ id,
140
+ username,
141
+ display_name,
142
+ verified,
143
+ admin
144
+ FROM developers
145
+ WHERE id = $1" ,
146
+ id
147
+ )
148
+ . fetch_optional ( & mut * conn)
149
+ . await
150
+ . map_err ( |e| {
151
+ log:: error!( "Failed to fetch developer {}: {}" , id, e) ;
152
+ ApiError :: DbError
153
+ } ) ?)
154
+ }
155
+
156
+ pub async fn get_one_by_username (
157
+ username : & str ,
158
+ conn : & mut PgConnection ,
159
+ ) -> Result < Option < Developer > , ApiError > {
160
+ Ok ( sqlx:: query_as!(
161
+ Developer ,
162
+ "SELECT
163
+ id,
164
+ username,
165
+ display_name,
166
+ verified,
167
+ admin
168
+ FROM developers
169
+ WHERE username = $1" ,
170
+ username
171
+ )
172
+ . fetch_optional ( & mut * conn)
173
+ . await
174
+ . map_err ( |e| {
175
+ log:: error!( "Failed to fetch developer {}: {}" , username, e) ;
176
+ ApiError :: DbError
177
+ } ) ?)
178
+ }
179
+
180
+ pub async fn get_all_for_mod (
181
+ mod_id : & str ,
182
+ conn : & mut PgConnection ,
183
+ ) -> Result < Vec < ModDeveloper > , ApiError > {
184
+ Ok ( sqlx:: query_as!(
185
+ ModDeveloper ,
186
+ "SELECT
187
+ dev.id,
188
+ dev.username,
189
+ dev.display_name,
190
+ md.is_owner
191
+ FROM developers dev
192
+ INNER JOIN mods_developers md ON dev.id = md.developer_id
193
+ WHERE md.mod_id = $1" ,
194
+ mod_id
195
+ )
196
+ . fetch_all ( conn)
197
+ . await
198
+ . map_err ( |e| {
199
+ log:: error!( "Failed to fetch developers for mod {}: {}" , mod_id, e) ;
200
+ ApiError :: DbError
201
+ } ) ?)
202
+ }
203
+
204
+ pub async fn get_all_for_mods (
205
+ mod_ids : & [ String ] ,
206
+ conn : & mut PgConnection ,
207
+ ) -> Result < HashMap < String , Vec < ModDeveloper > > , ApiError > {
208
+ if mod_ids. is_empty ( ) {
209
+ return Ok ( HashMap :: new ( ) ) ;
210
+ }
211
+ #[ derive( sqlx:: FromRow ) ]
212
+ struct QueryResult {
213
+ pub mod_id : String ,
214
+ pub id : i32 ,
215
+ pub username : String ,
216
+ pub display_name : String ,
217
+ pub is_owner : bool ,
218
+ }
219
+
220
+ let result = sqlx:: query_as!(
221
+ QueryResult ,
222
+ "SELECT
223
+ dev.id,
224
+ dev.username,
225
+ dev.display_name,
226
+ md.is_owner,
227
+ md.mod_id
228
+ FROM developers dev
229
+ INNER JOIN mods_developers md ON dev.id = md.developer_id
230
+ WHERE md.mod_id = ANY($1)" ,
231
+ mod_ids
232
+ )
233
+ . fetch_all ( conn)
234
+ . await
235
+ . map_err ( |e| {
236
+ log:: error!( "Failed to fetch developers for mods: {}" , e) ;
237
+ ApiError :: DbError
238
+ } ) ?;
239
+
240
+ let mut ret = HashMap :: new ( ) ;
241
+
242
+ for result_item in result {
243
+ ret. entry ( result_item. mod_id )
244
+ . or_default ( )
245
+ . push ( ModDeveloper {
246
+ id : result_item. id ,
247
+ username : result_item. username ,
248
+ display_name : result_item. display_name ,
249
+ is_owner : result_item. is_owner ,
250
+ } ) ;
251
+ }
252
+
253
+ Ok ( ret)
254
+ }
255
+
256
+ pub async fn has_access_to_mod (
257
+ dev_id : i32 ,
258
+ mod_id : & str ,
259
+ conn : & mut PgConnection ,
260
+ ) -> Result < bool , ApiError > {
261
+ Ok ( sqlx:: query!(
262
+ "SELECT developer_id FROM mods_developers
263
+ WHERE developer_id = $1
264
+ AND mod_id = $2" ,
265
+ dev_id,
266
+ mod_id
267
+ )
268
+ . fetch_optional ( & mut * conn)
269
+ . await
270
+ . map_err ( |e| {
271
+ log:: error!(
272
+ "Failed to find mod {} access for developer {}: {}" ,
273
+ mod_id,
274
+ dev_id,
275
+ e
276
+ ) ;
277
+ ApiError :: DbError
278
+ } ) ?
279
+ . is_some ( ) )
280
+ }
281
+
282
+ pub async fn owns_mod (
283
+ dev_id : i32 ,
284
+ mod_id : & str ,
285
+ conn : & mut PgConnection ,
286
+ ) -> Result < bool , ApiError > {
287
+ Ok ( sqlx:: query!(
288
+ "SELECT developer_id FROM mods_developers
289
+ WHERE developer_id = $1
290
+ AND mod_id = $2
291
+ AND is_owner = true" ,
292
+ dev_id,
293
+ mod_id
294
+ )
295
+ . fetch_optional ( & mut * conn)
296
+ . await
297
+ . map_err ( |e| {
298
+ log:: error!(
299
+ "Failed to check mod {} owner for developer {}: {}" ,
300
+ mod_id,
301
+ dev_id,
302
+ e
303
+ ) ;
304
+ ApiError :: DbError
305
+ } ) ?
306
+ . is_some ( ) )
307
+ }
308
+
59
309
pub async fn get_owner_for_mod (
60
310
mod_id : & str ,
61
311
conn : & mut PgConnection ,
62
- ) -> Result < FetchedDeveloper , ApiError > {
312
+ ) -> Result < Developer , ApiError > {
63
313
Ok ( sqlx:: query_as!(
64
- FetchedDeveloper ,
314
+ Developer ,
65
315
"SELECT
66
316
dev.id,
67
317
dev.username,
@@ -87,3 +337,58 @@ pub async fn get_owner_for_mod(
87
337
}
88
338
} ) ?)
89
339
}
340
+
341
+ pub async fn update_status (
342
+ dev_id : i32 ,
343
+ verified : bool ,
344
+ admin : bool ,
345
+ conn : & mut PgConnection ,
346
+ ) -> Result < Developer , ApiError > {
347
+ Ok ( sqlx:: query_as!(
348
+ Developer ,
349
+ "UPDATE developers
350
+ SET admin = $1,
351
+ verified = $2
352
+ WHERE id = $3
353
+ RETURNING
354
+ id,
355
+ username,
356
+ display_name,
357
+ verified,
358
+ admin" ,
359
+ admin,
360
+ verified,
361
+ dev_id
362
+ )
363
+ . fetch_one ( & mut * conn)
364
+ . map_err ( |e| {
365
+ log:: error!( "Failed to update developer {}: {}" , dev_id, e) ;
366
+ ApiError :: DbError
367
+ } ) ?)
368
+ }
369
+
370
+ pub async fn update_profile (
371
+ dev_id : i32 ,
372
+ display_name : & str ,
373
+ conn : & mut PgConnection ,
374
+ ) -> Result < Developer , ApiError > {
375
+ Ok ( sqlx:: query_as!(
376
+ Developer ,
377
+ "UPDATE developers
378
+ SET display_name = $1
379
+ WHERE id = $2
380
+ RETURNING
381
+ id,
382
+ username,
383
+ display_name,
384
+ verified,
385
+ admin" ,
386
+ display_name,
387
+ dev_id
388
+ )
389
+ . fetch_one ( & mut * conn)
390
+ . map_err ( |e| {
391
+ log:: error!( "Failed to update profile for {}: {}" , dev_id, e) ;
392
+ ApiError :: DbError
393
+ } ) ?)
394
+ }
0 commit comments