diff --git a/src/routes/mod_creation.rs b/src/routes/mod_creation.rs index 5d77b0bce..1a0409b98 100644 --- a/src/routes/mod_creation.rs +++ b/src/routes/mod_creation.rs @@ -203,7 +203,12 @@ async fn mod_create_inner( while let Some(chunk) = field.next().await { data.extend_from_slice(&chunk.map_err(CreateError::MultipartError)?); } - mod_create_data = Some(serde_json::from_slice(&data)?); + let create_data: ModCreateData = serde_json::from_slice(&data)?; + + check_length("mod_name", 3, 255, &*create_data.mod_name)?; + check_length("mod_description", 3, 2048, &*create_data.mod_description)?; + + mod_create_data = Some(create_data); continue; } @@ -211,9 +216,6 @@ async fn mod_create_inner( CreateError::InvalidInput(String::from("`data` field must come before file fields")) })?; - check_length("mod_name", 3, 255, &*create_data.mod_name)?; - check_length("mod_description", 3, 2048, &*create_data.mod_description)?; - let (file_name, file_extension) = super::version_creation::get_name_ext(&content_disposition)?; @@ -374,18 +376,35 @@ async fn mod_create_inner( file_name: upload_data.file_name.clone(), }); + let mut author_username = None; + let mut author_id = None; + let team = models::team_item::TeamBuilder { members: create_data .team_members .into_iter() - .map(|member| models::team_item::TeamMemberBuilder { - user_id: member.user_id.into(), - name: member.name, - role: member.role, + .map(|member| { + if member.role == crate::models::teams::OWNER_ROLE { + author_id = Some(member.user_id); + author_username = Some(member.name.clone()); + } + models::team_item::TeamMemberBuilder { + user_id: member.user_id.into(), + name: member.name, + role: member.role, + } }) .collect(), }; + let (author_username, author_id) = if let (Some(u), Some(id)) = (author_username, author_id) { + (u, id) + } else { + return Err(CreateError::InvalidInput(String::from( + "A mod must have an author", + ))); + }; + let team_id = team.insert(&mut *transaction).await?; let status = ModStatus::Processing; @@ -440,8 +459,8 @@ async fn mod_create_inner( versions: versions_list, page_url: format!("https://modrinth.com/mod/{}", mod_id), icon_url: mod_builder.icon_url.clone().unwrap(), - author: user.username, - author_url: format!("https://modrinth.com/user/{}", user.id), + author: author_username, + author_url: format!("https://modrinth.com/user/{}", author_id), // TODO: latest version info latest_version: String::new(), downloads: 0, diff --git a/src/search/indexing/curseforge_import.rs b/src/search/indexing/curseforge_import.rs index 46be0d412..0b1ef3a48 100644 --- a/src/search/indexing/curseforge_import.rs +++ b/src/search/indexing/curseforge_import.rs @@ -186,12 +186,15 @@ pub async fn index_curseforge( .date_modified .parse::>()?; - let mut author = String::new(); - let mut author_url = String::new(); + let author; + let author_url; - if curseforge_mod.authors.len() > 0 { - author = (&curseforge_mod.authors[0].name).to_string(); - author_url = (&curseforge_mod.authors[0].url).to_string(); + if let Some(user) = curseforge_mod.authors.get(0) { + author = user.name.clone(); + author_url = user.url.clone(); + } else { + author = String::from("unknown"); + author_url = curseforge_mod.website_url.clone(); } docs_to_add.push(UploadSearchMod { diff --git a/src/search/indexing/local_import.rs b/src/search/indexing/local_import.rs index d5794fab2..ae16c1d5d 100644 --- a/src/search/indexing/local_import.rs +++ b/src/search/indexing/local_import.rs @@ -12,14 +12,14 @@ pub async fn index_local(pool: PgPool) -> Result, IndexingE let mut docs_to_add: Vec = vec![]; - let mut results = sqlx::query!( + let mut mods = sqlx::query!( " SELECT m.id, m.title, m.description, m.downloads, m.icon_url, m.body_url, m.published, m.updated, m.team_id FROM mods m " ).fetch(&pool); - while let Some(result) = results.next().await { - if let Ok(result) = result { + while let Some(result) = mods.next().await { + if let Ok(mod_data) = result { let versions: Vec = sqlx::query!( " SELECT gv.version FROM versions @@ -27,7 +27,7 @@ pub async fn index_local(pool: PgPool) -> Result, IndexingE INNER JOIN game_versions gv ON gvv.game_version_id=gv.id WHERE versions.mod_id = $1 ", - result.id + mod_data.id ) .fetch_many(&pool) .try_filter_map(|e| async { Ok(e.right().map(|c| c.version)) }) @@ -41,7 +41,7 @@ pub async fn index_local(pool: PgPool) -> Result, IndexingE INNER JOIN loaders ON loaders.id = lv.loader_id WHERE versions.mod_id = $1 ", - result.id + mod_data.id ) .fetch_many(&pool) .try_filter_map(|e| async { Ok(e.right().map(|c| c.loader)) }) @@ -55,7 +55,7 @@ pub async fn index_local(pool: PgPool) -> Result, IndexingE INNER JOIN categories c ON mc.joining_category_id=c.id WHERE mc.joining_mod_id = $1 ", - result.id + mod_data.id ) .fetch_many(&pool) .try_filter_map(|e| async { Ok(e.right().map(|c| c.category)) }) @@ -71,32 +71,35 @@ pub async fn index_local(pool: PgPool) -> Result, IndexingE WHERE tm.team_id = $2 ", crate::models::teams::OWNER_ROLE, - result.team_id, + mod_data.team_id, ) .fetch_one(&pool) .await?; let mut icon_url = "".to_string(); - if let Some(url) = result.icon_url { + if let Some(url) = mod_data.icon_url { icon_url = url; } + let mod_id = crate::models::ids::ModId(mod_data.id as u64); + let author_id = crate::models::ids::UserId(user.id as u64); + docs_to_add.push(UploadSearchMod { - mod_id: format!("local-{}", crate::models::ids::ModId(result.id as u64)), - title: result.title, - description: result.description, + mod_id: format!("local-{}", mod_id), + title: mod_data.title, + description: mod_data.description, categories, versions, - downloads: result.downloads, - page_url: format!("https://modrinth.com/mod/{}", result.id), + downloads: mod_data.downloads, + page_url: format!("https://modrinth.com/mod/{}", mod_id), icon_url, author: user.username, - author_url: format!("https://modrinth.com/user/{}", user.id), - date_created: result.published, - created_timestamp: result.published.timestamp(), - date_modified: result.updated, - modified_timestamp: result.updated.timestamp(), + author_url: format!("https://modrinth.com/user/{}", author_id), + date_created: mod_data.published, + created_timestamp: mod_data.published.timestamp(), + date_modified: mod_data.updated, + modified_timestamp: mod_data.updated.timestamp(), latest_version: "".to_string(), // TODO: Info about latest version host: Cow::Borrowed("modrinth"), empty: Cow::Borrowed("{}{}{}"), diff --git a/src/search/mod.rs b/src/search/mod.rs index f40eaa0e8..9e67aab93 100644 --- a/src/search/mod.rs +++ b/src/search/mod.rs @@ -23,6 +23,8 @@ pub enum SearchError { IntParsingError(#[from] std::num::ParseIntError), #[error("Environment Error")] EnvError(#[from] dotenv::Error), + #[error("Invalid index to sort by: {0}")] + InvalidIndex(String), } impl actix_web::ResponseError for SearchError { @@ -32,6 +34,7 @@ impl actix_web::ResponseError for SearchError { SearchError::IndexDBError(..) => StatusCode::INTERNAL_SERVER_ERROR, SearchError::SerDeError(..) => StatusCode::BAD_REQUEST, SearchError::IntParsingError(..) => StatusCode::BAD_REQUEST, + SearchError::InvalidIndex(..) => StatusCode::BAD_REQUEST, } } @@ -42,6 +45,7 @@ impl actix_web::ResponseError for SearchError { SearchError::IndexDBError(..) => "indexdb_error", SearchError::SerDeError(..) => "invalid_input", SearchError::IntParsingError(..) => "invalid_input", + SearchError::InvalidIndex(..) => "invalid_input", }, description: &self.to_string(), }) @@ -161,8 +165,16 @@ pub async fn search_for_mod(info: &SearchRequest) -> Result "relevance_mods", + "downloads" => "downloads_mods", + "updated" => "updated_mods", + "newest" => "newest_mods", + i => return Err(SearchError::InvalidIndex(i.to_string())), + }; + let results = client - .get_index(format!("{}_mods", index).as_ref()) + .get_index(index) .await? .search::(&query) .await?;