From 26d9ef53987642aff1b77b0a415cc962ed6e7752 Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Wed, 11 May 2022 11:32:01 -0400 Subject: [PATCH] Rework download route (#345) --- sqlx-data.json | 95 ++++++++++++++++++++++-------------------- src/routes/admin.rs | 55 ++++++++++++++++++++++++ src/routes/mod.rs | 2 +- src/routes/versions.rs | 51 ----------------------- src/search/mod.rs | 4 +- 5 files changed, 108 insertions(+), 99 deletions(-) create mode 100644 src/routes/admin.rs diff --git a/sqlx-data.json b/sqlx-data.json index 24dff7bbc..9d3c2f0a5 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -95,18 +95,6 @@ "nullable": [] } }, - "02e0ebc0921f232ef2b199f8dbdfb5cd465855a85bcb0387069d74dc341a94a5": { - "query": "UPDATE versions\n SET downloads = downloads + 1\n WHERE (id = $1)", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - } - }, "03209c5bda2d704e688439919a7b3903db6ad7caebf7ddafb3ea52d312d47bfb": { "query": "\n INSERT INTO users (\n id, github_id, username, name, email,\n avatar_url, bio, created\n )\n VALUES (\n $1, $2, $3, $4, $5,\n $6, $7, $8\n )\n ", "describe": { @@ -284,6 +272,18 @@ ] } }, + "0dd7a3496dbd56f37640f46ff0575668fe75971aee32d0c5b1b24c35cd3b0861": { + "query": "UPDATE mods\n SET downloads = downloads + 1\n WHERE (id = $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + } + }, "0f29bb5ba767ebd0669c860994e48e3cb2674f0d53f6c4ab85c79d46b04cbb40": { "query": "\n SELECT EXISTS(SELECT 1 FROM mods WHERE id=$1)\n ", "describe": { @@ -528,6 +528,18 @@ "nullable": [] } }, + "1ba3b85bbdb0dd2360d6d18d3931ad1274d2d303601c5ee1b7dae2ba3e316658": { + "query": "UPDATE versions\n SET downloads = downloads + 1\n WHERE (id = $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + } + }, "1c7b0eb4341af5a7942e52f632cf582561f10b4b6a41a082fb8a60f04ac17c6e": { "query": "SELECT EXISTS(SELECT 1 FROM states WHERE id=$1)", "describe": { @@ -865,27 +877,6 @@ "nullable": [] } }, - "331041c6a4f27f4a6ac2873332074c0127e7368c8ab803843760530d29aaef08": { - "query": "SELECT id FROM versions\n WHERE (version_number = $1 AND mod_id = $2)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - }, - "nullable": [ - false - ] - } - }, "33a965c7dc615d3b701c05299889357db8dd36d378850625d2602ba471af4885": { "query": "\n UPDATE mods\n SET downloads = downloads + $1\n WHERE (id = $2)\n ", "describe": { @@ -2015,6 +2006,32 @@ ] } }, + "68f0e36e5dde4d05955de634227f3e65d16730e0ff260c7a33eff89b5f2ee972": { + "query": "\n SELECT v.id id, v.mod_id project_id FROM files f\n INNER JOIN versions v ON v.id = f.version_id\n WHERE f.url = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "project_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + } + }, "6a7b7704c2a0c52a70f5d881a1e6d3e8e77ddaa83ecc5688cd86bf327775fb76": { "query": "\n SELECT f.id id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n WHERE h.algorithm = $2 AND h.hash = $1\n ", "describe": { @@ -3241,18 +3258,6 @@ "nullable": [] } }, - "9bb993b9b743c3e6d3c8a9e4753983239b056cb9d4ec26e5fc8c6d4a5122e512": { - "query": "UPDATE mods\n SET downloads = downloads + 1\n WHERE (id = $1)", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - } - }, "9ceca63fb11f35f09f77bb9db175a1ac74dfcc2200c8134866922742fbbedea3": { "query": "\n UPDATE dependencies\n SET dependency_id = $2\n WHERE dependency_id = $1\n ", "describe": { diff --git a/src/routes/admin.rs b/src/routes/admin.rs new file mode 100644 index 000000000..8804c100b --- /dev/null +++ b/src/routes/admin.rs @@ -0,0 +1,55 @@ +use crate::routes::ApiError; +use crate::util::guards::admin_key_guard; +use actix_web::{patch, web, HttpResponse}; +use serde::Deserialize; +use sqlx::PgPool; + +#[derive(Deserialize)] +pub struct DownloadBody { + pub url: String, +} + +// This is an internal route, cannot be used without key +#[patch("/_count-download", guard = "admin_key_guard")] +pub async fn version_count_patch( + pool: web::Data, + download_body: web::Json, +) -> Result { + let version = sqlx::query!( + " + SELECT v.id id, v.mod_id project_id FROM files f + INNER JOIN versions v ON v.id = f.version_id + WHERE f.url = $1 + ", + download_body.url, + ) + .fetch_optional(pool.as_ref()) + .await? + .ok_or_else(|| { + ApiError::InvalidInput("Specified version does not exist!".to_string()) + })?; + + let mut transaction = pool.begin().await?; + + sqlx::query!( + "UPDATE versions + SET downloads = downloads + 1 + WHERE (id = $1)", + version.id + ) + .execute(&mut *transaction) + .await?; + + sqlx::query!( + "UPDATE mods + SET downloads = downloads + 1 + WHERE (id = $1)", + version.project_id + ) + .execute(&mut *transaction) + .await?; + + transaction.commit().await?; + + Ok(HttpResponse::Ok().body("")) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 5ac9128d9..899b36d9c 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,6 +1,7 @@ mod v1; pub use v1::v1_config; +mod admin; mod auth; mod health; mod index; @@ -87,7 +88,6 @@ pub fn versions_config(cfg: &mut web::ServiceConfig) { web::scope("version") .service(versions::version_get) .service(versions::version_delete) - .service(versions::version_count_patch) .service(version_creation::upload_file_to_version) .service(versions::version_edit), ); diff --git a/src/routes/versions.rs b/src/routes/versions.rs index b10e416b3..75e83c14f 100644 --- a/src/routes/versions.rs +++ b/src/routes/versions.rs @@ -1,11 +1,9 @@ use super::ApiError; use crate::database; -use crate::database::models as db_models; use crate::models; use crate::models::projects::{Dependency, Version}; use crate::models::teams::Permissions; use crate::util::auth::{get_user_from_headers, is_authorized}; -use crate::util::guards::admin_key_guard; use crate::util::validate::validation_errors_to_string; use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse}; use serde::{Deserialize, Serialize}; @@ -496,55 +494,6 @@ pub async fn version_edit( } } -// This is an internal route, cannot be used without key -#[patch( - "{project_id}/{version_name}/_count-download", - guard = "admin_key_guard" -)] -pub async fn version_count_patch( - info: web::Path<(models::ids::ProjectId, String)>, - pool: web::Data, -) -> Result { - let (project, version_name) = info.into_inner(); - let project = db_models::ids::ProjectId::from(project); - - let version = sqlx::query!( - "SELECT id FROM versions - WHERE (version_number = $1 AND mod_id = $2)", - version_name, - project as db_models::ids::ProjectId - ) - .fetch_optional(pool.as_ref()) - .await?; - let version = match version { - Some(version) => db_models::ids::VersionId(version.id), - _ => { - return Ok(HttpResponse::NotFound().body("Could not find version!")) - } - }; - - futures::future::try_join( - sqlx::query!( - "UPDATE versions - SET downloads = downloads + 1 - WHERE (id = $1)", - version as db_models::ids::VersionId - ) - .execute(pool.as_ref()), - sqlx::query!( - "UPDATE mods - SET downloads = downloads + 1 - WHERE (id = $1)", - project as db_models::ids::ProjectId - ) - .execute(pool.as_ref()), - ) - .await - .map_err(ApiError::SqlxDatabase)?; - - Ok(HttpResponse::Ok().body("")) -} - #[delete("{version_id}")] pub async fn version_delete( req: HttpRequest, diff --git a/src/search/mod.rs b/src/search/mod.rs index 71aae2bbd..c4ddee98b 100644 --- a/src/search/mod.rs +++ b/src/search/mod.rs @@ -160,8 +160,8 @@ pub async fn search_for_project( "relevance" => ("projects", ["downloads:desc"]), "downloads" => ("projects_filtered", ["downloads:desc"]), "follows" => ("projects_filtered", ["follows:desc"]), - "updated" => ("projects_filtered", ["date_created:desc"]), - "newest" => ("projects_filtered", ["date_modified:desc"]), + "updated" => ("projects_filtered", ["date_created:asc"]), + "newest" => ("projects_filtered", ["date_modified:asc"]), i => return Err(SearchError::InvalidIndex(i.to_string())), };