FlameAnvil Project Sync (#481)

* FlameAnvil Project Sync

* Perm fixes

* Fix compile

* Fix clippy + run prepare
This commit is contained in:
Geometrically
2022-11-20 19:50:14 -07:00
committed by GitHub
parent 589761bfd9
commit f259d81249
23 changed files with 2501 additions and 1493 deletions

View File

@@ -10,6 +10,7 @@ use crate::models::projects::{
VersionFile, VersionId, VersionType,
};
use crate::models::teams::Permissions;
use crate::queue::flameanvil::{FlameAnvilQueue, UploadFile};
use crate::routes::project_creation::{CreateError, UploadedFile};
use crate::util::auth::get_user_from_headers;
use crate::util::routes::read_from_field;
@@ -18,11 +19,13 @@ use crate::validate::{validate_file, ValidationResult};
use actix::fut::ready;
use actix_multipart::{Field, Multipart};
use actix_web::web::Data;
use actix_web::{post, HttpRequest, HttpResponse};
use actix_web::{post, web, HttpRequest, HttpResponse};
use chrono::Utc;
use futures::stream::StreamExt;
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPool;
use std::sync::Arc;
use tokio::sync::Mutex;
use validator::Validate;
#[derive(Serialize, Deserialize, Validate, Clone)]
@@ -68,7 +71,8 @@ pub async fn version_create(
req: HttpRequest,
mut payload: Multipart,
client: Data<PgPool>,
file_host: Data<std::sync::Arc<dyn FileHost + Send + Sync>>,
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
flame_anvil_queue: Data<Arc<Mutex<FlameAnvilQueue>>>,
) -> Result<HttpResponse, CreateError> {
let mut transaction = client.begin().await?;
let mut uploaded_files = Vec::new();
@@ -78,6 +82,7 @@ pub async fn version_create(
&mut payload,
&mut transaction,
&***file_host,
&flame_anvil_queue,
&mut uploaded_files,
)
.await;
@@ -108,6 +113,7 @@ async fn version_create_inner(
payload: &mut Multipart,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
file_host: &dyn FileHost,
flame_anvil_queue: &Mutex<FlameAnvilQueue>,
uploaded_files: &mut Vec<UploadedFile>,
) -> Result<HttpResponse, CreateError> {
let cdn_url = dotenvy::var("CDN_URL")?;
@@ -280,16 +286,29 @@ async fn version_create_inner(
let project_type = sqlx::query!(
"
SELECT name FROM project_types pt
INNER JOIN mods ON mods.project_type = pt.id
WHERE mods.id = $1
",
SELECT name FROM project_types pt
INNER JOIN mods ON mods.project_type = pt.id
WHERE mods.id = $1
",
version.project_id as models::ProjectId,
)
.fetch_one(&mut *transaction)
.await?
.name;
let flame_anvil_info = sqlx::query!(
"
SELECT m.flame_anvil_project, u.flame_anvil_key
FROM mods m
INNER JOIN users u ON m.flame_anvil_user = u.id
WHERE m.id = $1
",
version.project_id as models::ProjectId,
)
.fetch_optional(&mut *transaction)
.await?
.map(|x| (x.flame_anvil_project, x.flame_anvil_key));
let version_data = initial_version_data.clone().ok_or_else(|| {
CreateError::InvalidInput("`data` field is required".to_string())
})?;
@@ -297,6 +316,7 @@ async fn version_create_inner(
upload_file(
&mut field,
file_host,
version_data.file_parts.len(),
uploaded_files,
&mut version.files,
&mut version.dependencies,
@@ -310,6 +330,12 @@ async fn version_create_inner(
all_game_versions.clone(),
version_data.primary_file.is_some(),
version_data.primary_file.as_deref() == Some(name),
version_data.version_title.clone(),
version_data.version_body.clone().unwrap_or_default(),
version_data.release_channel.clone().to_string(),
flame_anvil_queue,
flame_anvil_info.clone().and_then(|x| x.0),
flame_anvil_info.and_then(|x| x.1),
transaction,
)
.await?;
@@ -344,9 +370,9 @@ async fn version_create_inner(
let users = sqlx::query!(
"
SELECT follower_id FROM mod_follows
WHERE mod_id = $1
",
SELECT follower_id FROM mod_follows
WHERE mod_id = $1
",
builder.project_id as crate::database::models::ids::ProjectId
)
.fetch_many(&mut *transaction)
@@ -363,7 +389,7 @@ async fn version_create_inner(
notification_type: Some("project_update".to_string()),
title: format!("**{}** has been updated!", result.title),
text: format!(
"The project, {}, has released a new version: {}",
"The project {} has released a new version: {}",
result.title,
version_data.version_number.clone()
),
@@ -428,10 +454,11 @@ async fn version_create_inner(
#[post("{version_id}/file")]
pub async fn upload_file_to_version(
req: HttpRequest,
url_data: actix_web::web::Path<(VersionId,)>,
url_data: web::Path<(VersionId,)>,
mut payload: Multipart,
client: Data<PgPool>,
file_host: Data<std::sync::Arc<dyn FileHost + Send + Sync>>,
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
flame_anvil_queue: Data<Arc<Mutex<FlameAnvilQueue>>>,
) -> Result<HttpResponse, CreateError> {
let mut transaction = client.begin().await?;
let mut uploaded_files = Vec::new();
@@ -444,6 +471,7 @@ pub async fn upload_file_to_version(
client,
&mut transaction,
&***file_host,
&flame_anvil_queue,
&mut uploaded_files,
version_id,
)
@@ -470,12 +498,14 @@ pub async fn upload_file_to_version(
result
}
#[allow(clippy::too_many_arguments)]
async fn upload_file_to_version_inner(
req: HttpRequest,
payload: &mut Multipart,
client: Data<PgPool>,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
file_host: &dyn FileHost,
flame_anvil_queue: &Mutex<FlameAnvilQueue>,
uploaded_files: &mut Vec<UploadedFile>,
version_id: models::VersionId,
) -> Result<HttpResponse, CreateError> {
@@ -578,6 +608,7 @@ async fn upload_file_to_version_inner(
upload_file(
&mut field,
file_host,
0,
uploaded_files,
&mut file_builders,
&mut dependencies,
@@ -596,6 +627,12 @@ async fn upload_file_to_version_inner(
all_game_versions.clone(),
true,
false,
version.name.clone(),
version.changelog.clone(),
version.version_type.clone(),
flame_anvil_queue,
None,
None,
transaction,
)
.await?;
@@ -620,6 +657,7 @@ async fn upload_file_to_version_inner(
pub async fn upload_file(
field: &mut Field,
file_host: &dyn FileHost,
total_files_len: usize,
uploaded_files: &mut Vec<UploadedFile>,
version_files: &mut Vec<VersionFileBuilder>,
dependencies: &mut Vec<DependencyBuilder>,
@@ -633,6 +671,12 @@ pub async fn upload_file(
all_game_versions: Vec<models::categories::GameVersion>,
ignore_primary: bool,
force_primary: bool,
version_display_name: String,
version_changelog: String,
version_type: String,
flame_anvil_queue: &Mutex<FlameAnvilQueue>,
flame_anvil_project: Option<i32>,
flame_anvil_key: Option<String>,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<(), CreateError> {
let (file_name, file_extension) = get_name_ext(content_disposition)?;
@@ -672,9 +716,9 @@ pub async fn upload_file(
data.clone().into(),
file_extension.to_string(),
project_type.to_string(),
loaders,
game_versions,
all_game_versions,
loaders.clone(),
game_versions.clone(),
all_game_versions.clone(),
)
.await?;
@@ -745,6 +789,43 @@ pub async fn upload_file(
}
}
let data = data.freeze();
let primary = (validation_result.is_passed()
&& version_files.iter().all(|x| !x.primary)
&& !ignore_primary)
|| force_primary
|| total_files_len == 1;
if primary {
if let Some(project_id) = flame_anvil_project {
if let Some(key) = flame_anvil_key {
let mut flame_anvil_queue = flame_anvil_queue.lock().await;
flame_anvil_queue
.upload_file(
&key,
project_id,
UploadFile {
loaders: loaders.into_iter().map(|x| x.0).collect(),
game_versions: game_versions
.into_iter()
.map(|x| x.0)
.collect(),
display_name: version_display_name,
changelog: version_changelog,
version_type,
},
&all_game_versions,
data.to_vec(),
file_name.to_string(),
content_type.to_string(),
)
.await?;
}
}
}
let file_path_encode = format!(
"data/{}/versions/{}/{}",
project_id,
@@ -755,7 +836,7 @@ pub async fn upload_file(
format!("data/{}/versions/{}/{}", project_id, version_id, &file_name);
let upload_data = file_host
.upload_file(content_type, &file_path, data.freeze())
.upload_file(content_type, &file_path, data)
.await?;
uploaded_files.push(UploadedFile {
@@ -777,7 +858,7 @@ pub async fn upload_file(
));
}
version_files.push(models::version_item::VersionFileBuilder {
version_files.push(VersionFileBuilder {
filename: file_name.to_string(),
url: format!("{}/{}", cdn_url, file_path_encode),
hashes: vec![
@@ -794,10 +875,7 @@ pub async fn upload_file(
hash: sha512_bytes,
},
],
primary: (validation_result.is_passed()
&& version_files.iter().all(|x| !x.primary)
&& !ignore_primary)
|| force_primary,
primary,
size: upload_data.content_length,
});