Skip to content

Commit

Permalink
add /v1/developers index
Browse files Browse the repository at this point in the history
  • Loading branch information
Fleeym committed Jun 5, 2024
1 parent 8b0c7ec commit db9d802
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 48 deletions.
34 changes: 34 additions & 0 deletions src/endpoints/developers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,40 @@ struct UpdateDeveloperPath {
id: i32,
}

#[derive(Deserialize)]
struct DeveloperIndexQuery {
query: Option<String>,
page: Option<i64>,
per_page: Option<i64>,
}

#[get("v1/developers")]
pub async fn developer_index(
data: web::Data<AppData>,
query: web::Query<DeveloperIndexQuery>,
) -> Result<impl Responder, ApiError> {
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;

let mut page = query.page.unwrap_or(1);
if page < 1 {
page = 1
}
let mut per_page = query.per_page.unwrap_or(15);
if per_page < 1 {
per_page = 1
}
if per_page > 100 {
per_page = 100
}

let result = Developer::get_index(&query.query, page, per_page, &mut pool).await?;

Ok(web::Json(ApiResponse {
error: "".to_string(),
payload: result,
}))
}

#[post("v1/mods/{id}/developers")]
pub async fn add_developer_to_mod(
data: web::Data<AppData>,
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ async fn main() -> anyhow::Result<()> {
.service(endpoints::mod_versions::update_version)
.service(endpoints::auth::github::poll_github_login)
.service(endpoints::auth::github::start_github_login)
.service(endpoints::developers::developer_index)
.service(endpoints::developers::add_developer_to_mod)
.service(endpoints::developers::remove_dev_from_mod)
.service(endpoints::developers::delete_tokens)
Expand Down
96 changes: 94 additions & 2 deletions src/types/models/developer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::{hash_map::Entry, HashMap};
use serde::{Deserialize, Serialize};
use sqlx::{PgConnection, Postgres, QueryBuilder};

use crate::types::api::ApiError;
use crate::types::api::{ApiError, PaginatedData};

#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct Developer {
Expand All @@ -22,7 +22,7 @@ pub struct DeveloperProfile {
pub admin: bool,
}

#[derive(Clone)]
#[derive(sqlx::FromRow, Clone)]
pub struct FetchedDeveloper {
pub id: i32,
pub username: String,
Expand All @@ -32,6 +32,98 @@ pub struct FetchedDeveloper {
}

impl Developer {
pub async fn get_index(
query: &Option<String>,
page: i64,
per_page: i64,
pool: &mut PgConnection,
) -> Result<PaginatedData<DeveloperProfile>, ApiError> {
let limit = per_page;
let offset = (page - 1) * per_page;

let name_query: Option<String> = query.as_ref().map(|q| format!("%{}%", q));

let mut builder: QueryBuilder<Postgres> = QueryBuilder::new(
r#"
SELECT
id,
username,
display_name,
verified,
admin
FROM developers
"#,
);

let mut counter: QueryBuilder<Postgres> = QueryBuilder::new(
r#"
SELECT COUNT(id)
FROM developers
"#,
);

if name_query.is_some() {
let sql = "WHERE username LIKE ";
builder.push(sql);
counter.push(sql);
builder.push_bind(name_query.clone().unwrap());
counter.push(name_query.clone().unwrap());
let sql = " OR WHERE display_name LIKE ";
builder.push(sql);
counter.push(sql);
builder.push(name_query.clone().unwrap());
counter.push(name_query.clone().unwrap());
}

builder.push(" GROUP BY id");
let sql = " LIMIT ";
builder.push(sql);
builder.push_bind(limit);
let sql = " OFFSET ";
builder.push(sql);
builder.push_bind(offset);

let result = match builder
.build_query_as::<FetchedDeveloper>()
.fetch_all(&mut *pool)
.await
{
Ok(r) => r,
Err(e) => {
log::error!("{}", e);
return Err(ApiError::DbError);
}
};

let result: Vec<DeveloperProfile> = result
.into_iter()
.map(|x| DeveloperProfile {
id: x.id,
username: x.username,
display_name: x.display_name,
verified: x.verified,
admin: x.admin,
})
.collect();

let count = match counter
.build_query_scalar()
.fetch_optional(&mut *pool)
.await
{
Ok(Some(c)) => c,
Ok(None) => 0,
Err(e) => {
log::error!("{}", e);
return Err(ApiError::DbError);
}
};

Ok(PaginatedData {
data: result,
count,
})
}
pub async fn create(
github_id: i64,
username: String,
Expand Down
2 changes: 1 addition & 1 deletion src/types/models/mod_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
mod_json::ModJson,
models::{
dependency::{Dependency, FetchedDependency},
incompatibility::{FetchedIncompatibility, Incompatibility, IncompatibilityImportance},
incompatibility::{FetchedIncompatibility, Incompatibility},
mod_version::ModVersion, mod_version_status::ModVersionStatusEnum,
},
},
Expand Down
46 changes: 1 addition & 45 deletions src/types/models/mod_version.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;

use chrono::Utc;
use serde::Serialize;
Expand Down Expand Up @@ -691,48 +691,4 @@ impl ModVersion {

Ok(())
}

/**
* @param to_check - map containing <MOD_ID -> HASHSET OF VERSIONS>
* @returns same map structure, with mods that were found and their versions
*/
pub async fn check_if_many_exist(
to_check: HashMap<String, HashSet<String>>,
pool: &mut PgConnection,
) -> Result<HashMap<String, HashSet<String>>, ApiError> {
let mut ret: HashMap<String, HashSet<String>> = HashMap::new();
let mut ids: Vec<String> = vec![];
let mut versions: Vec<String> = vec![];
for i in to_check {
ids.push(i.0);
for j in i.1 {
versions.push(j);
}
}

let r = match sqlx::query!(
r#"SELECT mod_id, version
FROM mod_versions
WHERE mod_id = ANY($1)
AND version = ANY($2)"#,
&ids,
&versions
)
.fetch_all(&mut *pool)
.await
{
Ok(r) => r,
Err(e) => {
log::error!("Failed to check if mods / versions exist");
log::error!("{}", e);
return Err(ApiError::DbError);
}
};

for i in r {
ret.entry(i.mod_id).or_default().insert(i.version);
}

Ok(ret)
}
}

0 comments on commit db9d802

Please sign in to comment.