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+ }
477
578pub async fn fetch_or_insert_github (
679 github_id : i64 ,
780 username : & str ,
881 conn : & mut PgConnection ,
9- ) -> Result < FetchedDeveloper , ApiError > {
82+ ) -> Result < Developer , ApiError > {
1083 match sqlx:: query_as!(
11- FetchedDeveloper ,
84+ Developer ,
1285 "SELECT
1386 id,
1487 username,
@@ -34,9 +107,9 @@ async fn insert_github(
34107 github_id : i64 ,
35108 username : & str ,
36109 conn : & mut PgConnection ,
37- ) -> Result < FetchedDeveloper , ApiError > {
110+ ) -> Result < Developer , ApiError > {
38111 Ok ( sqlx:: query_as!(
39- FetchedDeveloper ,
112+ Developer ,
40113 "INSERT INTO developers(username, display_name, github_user_id)
41114 VALUES ($1, $1, $2)
42115 RETURNING
@@ -56,12 +129,189 @@ async fn insert_github(
56129 } ) ?)
57130}
58131
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+
59309pub async fn get_owner_for_mod (
60310 mod_id : & str ,
61311 conn : & mut PgConnection ,
62- ) -> Result < FetchedDeveloper , ApiError > {
312+ ) -> Result < Developer , ApiError > {
63313 Ok ( sqlx:: query_as!(
64- FetchedDeveloper ,
314+ Developer ,
65315 "SELECT
66316 dev.id,
67317 dev.username,
@@ -87,3 +337,58 @@ pub async fn get_owner_for_mod(
87337 }
88338 } ) ?)
89339}
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