Version updates (#3626)

* Update some Labrinth dependencies

* Update some Labrinth dependencies

* Update some Labrinth dependencies

* Update zip in Labrinth

* Update itertools in Labrinth

* Update validator in labrinth

* Update thiserror in labrinth

* Update rust_decimal, redis, and deadpool-redis in labrinth

* Update totp-rs and spdx in labrinth

* Update maxminddb and tar in labrinth

* Update sentry and sentry-actix in labrinth

* Update image in labrinth

* Update lettre in labrinth

* Update derive-new and rust_iso3166 in labrinth

* Update async-stripe and json-patch in labrinth

* Update clap and iana-time-zone in labrinth

* Update labrinth to Rust 2024

* Cargo fmt

* Just do a full cargo update

* Update daedelus to Rust 2024

* Update daedelus_client to Rust 2024

* Set the formatting edition to 2024

* Fix formatting

IntelliJ messed up my formatting
This commit is contained in:
Josiah Glosson 2025-05-09 07:27:55 -05:00 committed by GitHub
parent 6e46317a37
commit 62de07e4e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
146 changed files with 1942 additions and 2311 deletions

3213
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,7 @@ uuid = { version = "1.1", features = ["serde", "v4"] }
tracing = "0.1.37"
tracing-error = "0.2.0"
dashmap = "6.0.1"
dashmap = "6.1.0"
paste = "1.0.15"
enumset = { version = "1.1", features = ["serde"] }

View File

@ -2,7 +2,7 @@
name = "daedalus_client"
version = "0.2.2"
authors = ["Jai A <jai@modrinth.com>"]
edition = "2021"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -15,25 +15,16 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde-xml-rs = "0.6.0"
lazy_static = "1.4.0"
thiserror = "1.0"
reqwest = { version = "0.12.5", default-features = false, features = [
"stream",
"json",
"rustls-tls-native-roots",
] }
thiserror = "2.0"
reqwest = { version = "0.12.15", default-features = false, features = ["stream", "json", "rustls-tls-native-roots"] }
async_zip = { version = "0.0.17", features = ["full"] }
chrono = { version = "0.4", features = ["serde"] }
bytes = "1.6.0"
rust-s3 = { version = "0.33.0", default-features = false, features = [
"fail-on-err",
"tags",
"tokio-rustls-tls",
"reqwest",
] }
dashmap = "5.5.3"
rust-s3 = { version = "0.35.1", default-features = false, features = ["fail-on-err", "tags", "tokio-rustls-tls"] }
dashmap = "6.1.0"
sha1_smol = { version = "1.0.0", features = ["std"] }
indexmap = { version = "2.2.6", features = ["serde"] }
itertools = "0.13.0"
itertools = "0.14.0"
tracing-error = "0.2.0"
tracing = "0.1"

View File

@ -12,7 +12,9 @@ pub enum ErrorKind {
SerdeJSON(#[from] serde_json::Error),
#[error("Error while deserializing XML: {0}")]
SerdeXML(#[from] serde_xml_rs::Error),
#[error("Failed to validate file checksum at url {url} with hash {hash} after {tries} tries")]
#[error(
"Failed to validate file checksum at url {url} with hash {hash} after {tries} tries"
)]
ChecksumFailure {
hash: String,
url: String,

View File

@ -1,6 +1,6 @@
use crate::util::{download_file, fetch_json, format_url};
use crate::{insert_mirrored_artifact, Error, MirrorArtifact, UploadFile};
use daedalus::modded::{Manifest, PartialVersionInfo, DUMMY_REPLACE_STRING};
use crate::{Error, MirrorArtifact, UploadFile, insert_mirrored_artifact};
use daedalus::modded::{DUMMY_REPLACE_STRING, Manifest, PartialVersionInfo};
use dashmap::DashMap;
use serde::Deserialize;
use std::sync::Arc;
@ -169,10 +169,11 @@ async fn fetch(
insert_mirrored_artifact(
&new_name,
None,
vec![lib
.url
vec![
lib.url
.clone()
.unwrap_or_else(|| maven_url.to_string())],
.unwrap_or_else(|| maven_url.to_string()),
],
false,
mirror_artifacts,
)?;

View File

@ -1,5 +1,5 @@
use crate::util::{download_file, fetch_json, fetch_xml, format_url};
use crate::{insert_mirrored_artifact, Error, MirrorArtifact, UploadFile};
use crate::{Error, MirrorArtifact, UploadFile, insert_mirrored_artifact};
use chrono::{DateTime, Utc};
use daedalus::get_path_from_artifact;
use daedalus::modded::PartialVersionInfo;
@ -7,8 +7,8 @@ use dashmap::DashMap;
use futures::io::Cursor;
use indexmap::IndexMap;
use itertools::Itertools;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Semaphore;
@ -589,8 +589,10 @@ async fn fetch(
mod_loader: &str,
version: &ForgeVersion,
) -> Result<String, Error> {
let extract_file =
read_file(zip, &value[1..value.len()])
let extract_file = read_file(
zip,
&value[1..value.len()],
)
.await?
.ok_or_else(|| {
crate::ErrorKind::InvalidInput(format!(
@ -622,10 +624,7 @@ async fn fetch(
let path = format!(
"com.modrinth.daedalus:{}-installer-extracts:{}:{}@{}",
mod_loader,
version.raw,
file_name,
ext
mod_loader, version.raw, file_name, ext
);
upload_files.insert(
@ -753,7 +752,8 @@ async fn fetch(
.rev()
.chunk_by(|x| x.game_version.clone())
.into_iter()
.map(|(game_version, loaders)| daedalus::modded::Version {
.map(|(game_version, loaders)| {
daedalus::modded::Version {
id: game_version,
stable: true,
loaders: loaders
@ -766,6 +766,7 @@ async fn fetch(
stable: false,
})
.collect(),
}
})
.collect(),
};

View File

@ -1,13 +1,13 @@
use crate::util::{
format_url, upload_file_to_bucket, upload_url_to_bucket_mirrors,
REQWEST_CLIENT,
REQWEST_CLIENT, format_url, upload_file_to_bucket,
upload_url_to_bucket_mirrors,
};
use daedalus::get_path_from_artifact;
use dashmap::{DashMap, DashSet};
use std::sync::Arc;
use tokio::sync::Semaphore;
use tracing_error::ErrorLayer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
mod error;
mod fabric;

View File

@ -1,11 +1,11 @@
use crate::util::fetch_json;
use crate::{
util::download_file, util::format_url, util::sha1_async, Error,
MirrorArtifact, UploadFile,
Error, MirrorArtifact, UploadFile, util::download_file, util::format_url,
util::sha1_async,
};
use daedalus::minecraft::{
merge_partial_library, Library, PartialLibrary, VersionInfo,
VersionManifest, VERSION_MANIFEST_URL,
Library, PartialLibrary, VERSION_MANIFEST_URL, VersionInfo,
VersionManifest, merge_partial_library,
};
use dashmap::DashMap;
use serde::Deserialize;

View File

@ -7,7 +7,7 @@ use std::sync::Arc;
use tokio::sync::Semaphore;
lazy_static::lazy_static! {
static ref BUCKET : Bucket = {
static ref BUCKET: Bucket = {
let region = dotenvy::var("S3_REGION").unwrap();
let b = Bucket::new(
&dotenvy::var("S3_BUCKET_NAME").unwrap(),
@ -31,9 +31,9 @@ lazy_static::lazy_static! {
).unwrap();
if region == "path-style" {
b.with_path_style()
*b.with_path_style()
} else {
b
*b
}
};
}
@ -203,7 +203,7 @@ pub async fn download_file(
inner: err,
item: url.to_string(),
}
.into())
.into());
}
}
}

View File

@ -2,7 +2,7 @@
name = "labrinth"
version = "2.7.0"
authors = ["geometrically <jai@modrinth.com>"]
edition = "2018"
edition = "2024"
license = "AGPL-3.0"
# This seems redundant, but it's necessary for Docker to work
@ -11,17 +11,17 @@ name = "labrinth"
path = "src/main.rs"
[dependencies]
actix-web = "4.4.1"
actix-web = "4.10.2"
actix-rt = "2.9.0"
actix-multipart = "0.6.1"
actix-cors = "0.7.0"
actix-multipart = "0.7.2"
actix-cors = "0.7.1"
actix-ws = "0.3.0"
actix-files = "0.6.5"
prometheus = "0.13.4"
prometheus = "0.13.4" # Locked on 0.13 until actix updates to 0.14
actix-web-prom = { version = "0.9.0", features = ["process"] }
tracing = "0.1.41"
tracing-actix-web = "0.7.16"
tracing-actix-web = "0.7.18"
console-subscriber = "0.4.1"
tokio = { version = "1.35.1", features = ["sync", "rt-multi-thread"] }
@ -30,14 +30,15 @@ tokio-stream = "0.1.14"
futures = "0.3.30"
futures-util = "0.3.30"
async-trait = "0.1.70"
dashmap = "5.4.0"
dashmap = "6.1.0"
lazy_static = "1.4.0"
meilisearch-sdk = "0.27.1"
rust-s3 = "0.33.0"
reqwest = { version = "0.11.18", features = ["json", "multipart"] }
hyper = { version = "0.14", features = ["full"] }
hyper-tls = "0.5.0"
meilisearch-sdk = "0.28.0"
rust-s3 = { version = "0.35.1", default-features = false, features = ["fail-on-err", "tags", "tokio-rustls-tls"] }
reqwest = { version = "0.12.15", features = ["json", "multipart"] }
hyper = { version = "1.6", features = ["full"] }
hyper-tls = "0.6.0"
hyper-util = "0.1.11"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
@ -46,34 +47,34 @@ chrono = { version = "0.4.26", features = ["serde"] }
yaserde = "0.12.0"
yaserde_derive = "0.12.0"
rand = "0.8.5"
rand_chacha = "0.3.1"
rand = "0.8.5" # Locked on 0.8 until argon2 updates to 0.9
rand_chacha = "0.3.1" # Locked on 0.3 until we can update rand to 0.9
bytes = "1.4.0"
base64 = "0.21.7"
sha1 = { version = "0.6.1", features = ["std"] }
sha2 = "0.9.9"
hmac = "0.11.0"
base64 = "0.22.1"
sha1 = { version = "0.10.6", features = ["std"] }
sha2 = "0.10.9"
hmac = "0.12.1"
argon2 = { version = "0.5.0", features = ["std"] }
murmur2 = "0.1.0"
bitflags = "2.4.0"
hex = "0.4.3"
zxcvbn = "2.2.2"
zxcvbn = "3.1.0"
totp-rs = { version = "5.0.2", features = ["gen_secret"] }
url = "2.4.0"
urlencoding = "2.1.2"
zip = "0.6.6"
zip = "2.6.1"
itertools = "0.12.0"
itertools = "0.14.0"
validator = { version = "0.16.1", features = ["derive", "phone"] }
validator = { version = "0.20.0", features = ["derive"] }
regex = "1.10.2"
censor = "0.3.0"
spdx = { version = "0.10.3", features = ["text"] }
dotenvy = "0.15.7"
thiserror = "1.0.56"
thiserror = "2.0.12"
either = "1.13"
sqlx = { version = "0.8.2", features = [
@ -89,26 +90,19 @@ rust_decimal = { version = "1.33.1", features = [
"serde-with-float",
"serde-with-str",
] }
redis = { version = "0.27.5", features = ["tokio-comp", "ahash", "r2d2"] }
deadpool-redis = "0.18.0"
clickhouse = { version = "0.11.2", features = ["uuid", "time"] }
redis = { version = "0.29.5", features = ["tokio-comp", "ahash", "r2d2"] } # Locked on 0.29 until deadpool-redis updates to 0.30
deadpool-redis = "0.20.0"
clickhouse = { version = "0.13.2", features = ["uuid", "time"] }
uuid = { version = "1.2.2", features = ["v4", "fast-rng", "serde"] }
maxminddb = "0.24.0"
maxminddb = "0.26.0"
flate2 = "1.0.25"
tar = "0.4.38"
sentry = { version = "0.34.0", default-features = false, features = [
"backtrace",
"contexts",
"debug-images",
"panic",
"rustls",
"reqwest",
] }
sentry-actix = "0.34.0"
sentry = { version = "0.37.0", default-features = false, features = ["backtrace", "contexts", "debug-images", "panic", "rustls", "reqwest"] }
sentry-actix = "0.37.0"
image = "0.24.6"
image = "0.25.6"
color-thief = "0.2.2"
webp = "0.3.0"
@ -116,12 +110,12 @@ woothee = "0.13.0"
lettre = "0.11.3"
derive-new = "0.6.0"
derive-new = "0.7.0"
rust_iso3166 = "0.1.11"
async-stripe = { version = "0.39.1", features = ["runtime-tokio-hyper-rustls"] }
async-stripe = { version = "0.41.0", features = ["runtime-tokio-hyper-rustls"] }
rusty-money = "0.4.1"
json-patch = "*"
json-patch = "4.0.0"
ariadne = { path = "../../packages/ariadne" }

View File

@ -1,9 +1,9 @@
use crate::database;
use crate::database::models::Collection;
use crate::database::models::project_item::QueryProject;
use crate::database::models::version_item::QueryVersion;
use crate::database::models::Collection;
use crate::database::redis::RedisPool;
use crate::database::{models, Project, Version};
use crate::database::{Project, Version, models};
use crate::models::users::User;
use crate::routes::ApiError;
use itertools::Itertools;

View File

@ -1,5 +1,5 @@
use lettre::message::header::ContentType;
use lettre::message::Mailbox;
use lettre::message::header::ContentType;
use lettre::transport::smtp::authentication::Credentials;
use lettre::transport::smtp::client::{Tls, TlsParameters};
use lettre::{Address, Message, SmtpTransport, Transport};

View File

@ -15,8 +15,8 @@ pub use validate::{check_is_moderator_from_headers, get_user_from_headers};
use crate::file_hosting::FileHostingError;
use crate::models::error::ApiError;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use actix_web::http::StatusCode;
use thiserror::Error;
#[derive(Error, Debug)]

View File

@ -1,8 +1,8 @@
use super::ValidatedRedirectUri;
use crate::auth::AuthenticationError;
use crate::models::error::ApiError;
use actix_web::http::{header::LOCATION, StatusCode};
use actix_web::HttpResponse;
use actix_web::http::{StatusCode, header::LOCATION};
use ariadne::ids::DecodingError;
#[derive(thiserror::Error, Debug)]
@ -122,7 +122,9 @@ pub enum OAuthErrorType {
"The provided redirect URI did not match any configured in the client"
)]
RedirectUriNotConfigured(String),
#[error("The provided scope was malformed or did not correspond to known scopes ({0})")]
#[error(
"The provided scope was malformed or did not correspond to known scopes ({0})"
)]
FailedScopeParse(bitflags::parser::ParseError),
#[error(
"The provided scope requested scopes broader than the developer app is configured with"
@ -138,9 +140,13 @@ pub enum OAuthErrorType {
ClientAuthenticationFailed,
#[error("The provided authorization grant code was invalid")]
InvalidAuthCode,
#[error("The provided client id did not match the id this authorization code was granted to")]
#[error(
"The provided client id did not match the id this authorization code was granted to"
)]
UnauthorizedClient,
#[error("The provided redirect URI did not exactly match the uri originally provided when this flow began")]
#[error(
"The provided redirect URI did not exactly match the uri originally provided when this flow began"
)]
RedirectUriChanged(Option<String>),
#[error("The provided grant type ({0}) must be \"authorization_code\"")]
OnlySupportsAuthorizationCodeGrant(String),

View File

@ -6,22 +6,21 @@ use crate::database::models::oauth_client_authorization_item::OAuthClientAuthori
use crate::database::models::oauth_client_item::OAuthClient as DBOAuthClient;
use crate::database::models::oauth_token_item::OAuthAccessToken;
use crate::database::models::{
generate_oauth_access_token_id, generate_oauth_client_authorization_id,
OAuthClientAuthorizationId,
OAuthClientAuthorizationId, generate_oauth_access_token_id,
generate_oauth_client_authorization_id,
};
use crate::database::redis::RedisPool;
use crate::models;
use crate::models::ids::OAuthClientId;
use crate::models::pats::Scopes;
use crate::queue::session::AuthQueue;
use actix_web::http::header::LOCATION;
use actix_web::http::header::{CACHE_CONTROL, LOCATION, PRAGMA};
use actix_web::web::{Data, Query, ServiceConfig};
use actix_web::{get, post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, get, post, web};
use chrono::Duration;
use rand::distributions::Alphanumeric;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use reqwest::header::{CACHE_CONTROL, PRAGMA};
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPool;

View File

@ -6,8 +6,8 @@ use crate::models::pats::Scopes;
use crate::models::users::User;
use crate::queue::session::AuthQueue;
use crate::routes::internal::session::get_session_metadata;
use actix_web::http::header::{HeaderValue, AUTHORIZATION};
use actix_web::HttpRequest;
use actix_web::http::header::{AUTHORIZATION, HeaderValue};
use chrono::Utc;
pub async fn get_user_from_headers<'a, E>(

View File

@ -1,5 +1,6 @@
use hyper::client::HttpConnector;
use hyper_tls::{native_tls, HttpsConnector};
use hyper_tls::{HttpsConnector, native_tls};
use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::rt::TokioExecutor;
mod fetch;
@ -22,7 +23,8 @@ pub async fn init_client_with_database(
let https_connector =
HttpsConnector::from((http_connector, tls_connector));
let hyper_client =
hyper::client::Client::builder().build(https_connector);
hyper_util::client::legacy::Client::builder(TokioExecutor::new())
.build(https_connector);
clickhouse::Client::with_http_client(hyper_client)
.with_url(dotenvy::var("CLICKHOUSE_URL").unwrap())

View File

@ -2,8 +2,8 @@ use std::collections::HashMap;
use crate::database::redis::RedisPool;
use super::ids::*;
use super::DatabaseError;
use super::ids::*;
use futures::TryStreamExt;
use serde::{Deserialize, Serialize};

View File

@ -1,14 +1,14 @@
use super::ids::*;
use crate::auth::oauth::uris::OAuthRedirectUris;
use crate::auth::AuthProvider;
use crate::auth::oauth::uris::OAuthRedirectUris;
use crate::database::models::DatabaseError;
use crate::database::redis::RedisPool;
use crate::models::pats::Scopes;
use chrono::Duration;
use rand::distributions::Alphanumeric;
use rand::Rng;
use rand_chacha::rand_core::SeedableRng;
use rand::distributions::Alphanumeric;
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
use serde::{Deserialize, Serialize};
const FLOWS_NAMESPACE: &str = "flows";

View File

@ -12,10 +12,10 @@ use serde_json::json;
use crate::database::redis::RedisPool;
use super::{
DatabaseError, LoaderFieldEnumValueId,
loader_fields::{
LoaderFieldEnum, LoaderFieldEnumValue, VersionField, VersionFieldValue,
},
DatabaseError, LoaderFieldEnumValueId,
};
#[derive(Clone, Serialize, Deserialize, Debug)]

View File

@ -1,8 +1,8 @@
use std::collections::HashMap;
use std::hash::Hasher;
use super::ids::*;
use super::DatabaseError;
use super::ids::*;
use crate::database::redis::RedisPool;
use chrono::DateTime;
use chrono::Utc;

View File

@ -5,7 +5,7 @@ use futures::TryStreamExt;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use super::{ids::*, TeamMember};
use super::{TeamMember, ids::*};
use serde::{Deserialize, Serialize};
const ORGANIZATIONS_NAMESPACE: &str = "organizations";

View File

@ -1,5 +1,5 @@
use crate::database::models::{
product_item, DatabaseError, ProductId, ProductPriceId,
DatabaseError, ProductId, ProductPriceId, product_item,
};
use crate::database::redis::RedisPool;
use crate::models::billing::{Price, ProductMetadata};

View File

@ -2,7 +2,7 @@ use super::loader_fields::{
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField,
VersionField,
};
use super::{ids::*, User};
use super::{User, ids::*};
use crate::database::models;
use crate::database::models::DatabaseError;
use crate::database::redis::RedisPool;

View File

@ -1,4 +1,4 @@
use super::{ids::*, Organization, Project};
use super::{Organization, Project, ids::*};
use crate::{
database::redis::RedisPool,
models::teams::{OrganizationPermissions, ProjectPermissions},

View File

@ -1,6 +1,6 @@
use super::DatabaseError;
use super::ids::*;
use super::loader_fields::VersionField;
use super::DatabaseError;
use crate::database::models::loader_fields::{
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField,
};

View File

@ -4,7 +4,7 @@ use chrono::{TimeZone, Utc};
use dashmap::DashMap;
use deadpool_redis::{Config, Runtime};
use prometheus::{IntGauge, Registry};
use redis::{cmd, Cmd, ExistenceCheck, SetExpiry, SetOptions};
use redis::{Cmd, ExistenceCheck, SetExpiry, SetOptions, cmd};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

View File

@ -1,7 +1,9 @@
use super::authorization::UploadUrlData;
use crate::file_hosting::FileHostingError;
use bytes::Bytes;
use hex::ToHex;
use serde::{Deserialize, Serialize};
use sha1::Digest;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
@ -35,7 +37,7 @@ pub async fn upload_file(
.header(reqwest::header::CONTENT_LENGTH, file_bytes.len())
.header(
"X-Bz-Content-Sha1",
sha1::Sha1::from(&file_bytes).hexdigest(),
sha1::Sha1::digest(&file_bytes).encode_hex::<String>(),
)
.body(file_bytes)
.send()

View File

@ -2,6 +2,7 @@ use super::{DeleteFileData, FileHost, FileHostingError, UploadFileData};
use async_trait::async_trait;
use bytes::Bytes;
use chrono::Utc;
use hex::ToHex;
use sha2::Digest;
#[derive(Default)]
@ -27,7 +28,7 @@ impl FileHost for MockHost {
std::fs::create_dir_all(
path.parent().ok_or(FileHostingError::InvalidFilename)?,
)?;
let content_sha1 = sha1::Sha1::from(&file_bytes).hexdigest();
let content_sha1 = sha1::Sha1::digest(&file_bytes).encode_hex();
let content_sha512 = format!("{:x}", sha2::Sha512::digest(&file_bytes));
std::fs::write(path, &*file_bytes)?;

View File

@ -4,6 +4,7 @@ use crate::file_hosting::{
use async_trait::async_trait;
use bytes::Bytes;
use chrono::Utc;
use hex::ToHex;
use s3::bucket::Bucket;
use s3::creds::Credentials;
use s3::region::Region;
@ -52,7 +53,7 @@ impl S3Host {
)
})?;
Ok(S3Host { bucket })
Ok(S3Host { bucket: *bucket })
}
}
@ -64,7 +65,7 @@ impl FileHost for S3Host {
file_name: &str,
file_bytes: Bytes,
) -> Result<UploadFileData, FileHostingError> {
let content_sha1 = sha1::Sha1::from(&file_bytes).hexdigest();
let content_sha1 = sha1::Sha1::digest(&file_bytes).encode_hex();
let content_sha512 = format!("{:x}", sha2::Sha512::digest(&file_bytes));
self.bucket

View File

@ -374,7 +374,10 @@ pub fn check_env_vars() -> bool {
failed |= check_var::<String>("MOCK_FILE_PATH");
}
Some(backend) => {
warn!("Variable `STORAGE_BACKEND` contains an invalid value: {}. Expected \"backblaze\", \"s3\", or \"local\".", backend);
warn!(
"Variable `STORAGE_BACKEND` contains an invalid value: {}. Expected \"backblaze\", \"s3\", or \"local\".",
backend
);
failed |= true;
}
_ => {
@ -387,12 +390,16 @@ pub fn check_env_vars() -> bool {
failed |= check_var::<usize>("VERSION_INDEX_INTERVAL");
if parse_strings_from_var("WHITELISTED_MODPACK_DOMAINS").is_none() {
warn!("Variable `WHITELISTED_MODPACK_DOMAINS` missing in dotenv or not a json array of strings");
warn!(
"Variable `WHITELISTED_MODPACK_DOMAINS` missing in dotenv or not a json array of strings"
);
failed |= true;
}
if parse_strings_from_var("ALLOWED_CALLBACK_URLS").is_none() {
warn!("Variable `ALLOWED_CALLBACK_URLS` missing in dotenv or not a json array of strings");
warn!(
"Variable `ALLOWED_CALLBACK_URLS` missing in dotenv or not a json array of strings"
);
failed |= true;
}

View File

@ -17,7 +17,7 @@ use tracing_actix_web::TracingLogger;
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
#[allow(non_upper_case_globals)]
#[export_name = "malloc_conf"]
#[unsafe(export_name = "malloc_conf")]
pub static malloc_conf: &[u8] =
b"prof:true,prof_active:true,lg_prof_sample:19\0";
@ -63,8 +63,10 @@ async fn main() -> std::io::Result<()> {
});
if sentry.is_enabled() {
info!("Enabled Sentry integration");
unsafe {
std::env::set_var("RUST_BACKTRACE", "1");
}
}
if args.run_background_task.is_none() {
info!(

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
use super::super::ids::OrganizationId;
use super::super::teams::TeamId;
use super::super::users::UserId;
use crate::database::models::{version_item, DatabaseError};
use crate::database::models::{DatabaseError, version_item};
use crate::database::redis::RedisPool;
use crate::models::ids::{ProjectId, VersionId};
use crate::models::projects::{

View File

@ -15,8 +15,8 @@ pub use super::threads::ThreadMessageId;
pub use crate::models::billing::{
ChargeId, ProductId, ProductPriceId, UserSubscriptionId,
};
use ariadne::ids::base62_id_impl;
pub use ariadne::ids::Base62Id;
use ariadne::ids::base62_id_impl;
pub use ariadne::users::UserId;
base62_id_impl!(ProjectId, ProjectId);

View File

@ -92,18 +92,26 @@ impl From<DBNotification> for Notification {
..
} => (
"You have been invited to join a team!".to_string(),
format!("An invite has been sent for you to be {role} of a team"),
format!(
"An invite has been sent for you to be {role} of a team"
),
format!("/project/{project_id}"),
vec![
NotificationAction {
name: "Accept".to_string(),
action_route: ("POST".to_string(), format!("team/{team_id}/join")),
action_route: (
"POST".to_string(),
format!("team/{team_id}/join"),
),
},
NotificationAction {
name: "Deny".to_string(),
action_route: (
"DELETE".to_string(),
format!("team/{team_id}/members/{}", UserId::from(notif.user_id)),
format!(
"team/{team_id}/members/{}",
UserId::from(notif.user_id)
),
),
},
],
@ -114,7 +122,8 @@ impl From<DBNotification> for Notification {
team_id,
..
} => (
"You have been invited to join an organization!".to_string(),
"You have been invited to join an organization!"
.to_string(),
format!(
"An invite has been sent for you to be {role} of an organization"
),
@ -122,7 +131,10 @@ impl From<DBNotification> for Notification {
vec![
NotificationAction {
name: "Accept".to_string(),
action_route: ("POST".to_string(), format!("team/{team_id}/join")),
action_route: (
"POST".to_string(),
format!("team/{team_id}/join"),
),
},
NotificationAction {
name: "Deny".to_string(),

View File

@ -15,7 +15,7 @@ pub struct PackFormat {
pub name: String,
#[validate(length(max = 2048))]
pub summary: Option<String>,
#[validate]
#[validate(nested)]
pub files: Vec<PackFile>,
pub dependencies: std::collections::HashMap<PackDependency, String>,
}

View File

@ -61,7 +61,9 @@ impl MaxMindIndexer {
}
if should_panic {
panic!("Unable to download maxmind database- did you get a license key?")
panic!(
"Unable to download maxmind database- did you get a license key?"
)
} else {
warn!("Unable to download maxmind database.");
@ -73,7 +75,11 @@ impl MaxMindIndexer {
let maxmind = self.reader.read().await;
if let Some(ref maxmind) = *maxmind {
maxmind.lookup::<Country>(ip.into()).ok().and_then(|x| {
maxmind
.lookup::<Country>(ip.into())
.ok()
.flatten()
.and_then(|x| {
x.country.and_then(|x| x.iso_code.map(|x| x.to_string()))
})
} else {

View File

@ -10,8 +10,10 @@ use crate::models::projects::ProjectStatus;
use crate::models::threads::MessageBody;
use crate::routes::ApiError;
use dashmap::DashSet;
use hex::ToHex;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use sha1::Digest;
use sqlx::PgPool;
use std::collections::HashMap;
use std::io::{Cursor, Read};
@ -329,7 +331,7 @@ impl AutomatedModerationQueue {
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
let hash = sha1::Sha1::from(&contents).hexdigest();
let hash = sha1::Sha1::digest(&contents).encode_hex::<String>();
let murmur = hash_flame_murmur32(contents);
hashes.push((

View File

@ -13,8 +13,8 @@ use rust_decimal::Decimal;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::postgres::PgQueryResult;
use sqlx::PgPool;
use sqlx::postgres::PgQueryResult;
use std::collections::HashMap;
use tokio::sync::RwLock;

View File

@ -8,8 +8,8 @@ use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::util::date::get_current_tenths_of_ms;
use crate::util::env::parse_strings_from_var;
use actix_web::{post, web};
use actix_web::{HttpRequest, HttpResponse};
use actix_web::{post, web};
use serde::Deserialize;
use sqlx::PgPool;
use std::collections::HashMap;

View File

@ -1,7 +1,7 @@
use crate::routes::ApiError;
use crate::util::cors::default_cors;
use crate::util::guards::admin_key_guard;
use actix_web::{get, HttpResponse};
use actix_web::{HttpResponse, get};
use prometheus::{IntGauge, Registry};
use std::time::Duration;

View File

@ -1,4 +1,4 @@
use actix_web::{get, HttpResponse};
use actix_web::{HttpResponse, get};
use serde_json::json;
#[get("/")]

View File

@ -14,7 +14,7 @@ use crate::routes::ApiError;
use crate::search::SearchConfig;
use crate::util::date::get_current_tenths_of_ms;
use crate::util::guards::admin_key_guard;
use actix_web::{get, patch, post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, get, patch, post, web};
use serde::Deserialize;
use sqlx::PgPool;
use std::collections::HashMap;
@ -237,7 +237,10 @@ pub async fn delphi_result_ingest(
.await
.ok();
let mut thread_header = format!("Suspicious traces found at [version {}](https://modrinth.com/project/{}/version/{})", body.version_id, body.project_id, body.version_id);
let mut thread_header = format!(
"Suspicious traces found at [version {}](https://modrinth.com/project/{}/version/{})",
body.version_id, body.project_id, body.version_id
);
for (issue, trace) in &body.issues {
for path in trace.keys() {

View File

@ -14,11 +14,11 @@ use crate::models::pats::Scopes;
use crate::models::users::Badges;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post, web};
use ariadne::ids::base62_impl::{parse_base62, to_base62};
use chrono::Utc;
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use rust_decimal::prelude::ToPrimitive;
use serde::Serialize;
use serde_with::serde_derive::Deserialize;
use sqlx::{PgPool, Postgres, Transaction};
@ -1992,9 +1992,18 @@ pub async fn stripe_webhook(
let _ = send_email(
email,
"Payment Failed for Modrinth",
&format!("Our attempt to collect payment for {money} from the payment card on file was unsuccessful."),
&format!(
"Our attempt to collect payment for {money} from the payment card on file was unsuccessful."
),
"Please visit the following link below to update your payment method or contact your card provider. If the button does not work, you can copy the link and paste it into your browser.",
Some(("Update billing settings", &format!("{}/{}", dotenvy::var("SITE_URL")?, dotenvy::var("SITE_BILLING_PATH")?))),
Some((
"Update billing settings",
&format!(
"{}/{}",
dotenvy::var("SITE_URL")?,
dotenvy::var("SITE_BILLING_PATH")?
),
)),
);
}

View File

@ -1,29 +1,29 @@
use crate::auth::email::send_email;
use crate::auth::validate::get_user_record_from_bearer_token;
use crate::auth::{get_user_from_headers, AuthProvider, AuthenticationError};
use crate::auth::{AuthProvider, AuthenticationError, get_user_from_headers};
use crate::database::models::flow_item::Flow;
use crate::database::redis::RedisPool;
use crate::file_hosting::FileHost;
use crate::models::pats::Scopes;
use crate::models::users::{Badges, Role};
use crate::queue::session::AuthQueue;
use crate::routes::internal::session::issue_session;
use crate::routes::ApiError;
use crate::routes::internal::session::issue_session;
use crate::util::captcha::check_hcaptcha;
use crate::util::env::parse_strings_from_var;
use crate::util::ext::get_image_ext;
use crate::util::img::upload_image_optimized;
use crate::util::validate::{validation_errors_to_string, RE_URL_SAFE};
use actix_web::web::{scope, Data, Query, ServiceConfig};
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use crate::util::validate::{RE_URL_SAFE, validation_errors_to_string};
use actix_web::web::{Data, Query, ServiceConfig, scope};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post, web};
use argon2::password_hash::SaltString;
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use ariadne::ids::base62_impl::{parse_base62, to_base62};
use ariadne::ids::random_base62_rng;
use base64::Engine;
use chrono::{Duration, Utc};
use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
use reqwest::header::AUTHORIZATION;
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPool;
@ -31,6 +31,7 @@ use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use validator::Validate;
use zxcvbn::Score;
pub fn config(cfg: &mut ServiceConfig) {
cfg.service(
@ -261,12 +262,16 @@ impl AuthProvider {
AuthProvider::Discord => {
let client_id = dotenvy::var("DISCORD_CLIENT_ID")?;
format!("https://discord.com/api/oauth2/authorize?client_id={client_id}&state={state}&response_type=code&scope=identify%20email&redirect_uri={redirect_uri}")
format!(
"https://discord.com/api/oauth2/authorize?client_id={client_id}&state={state}&response_type=code&scope=identify%20email&redirect_uri={redirect_uri}"
)
}
AuthProvider::Microsoft => {
let client_id = dotenvy::var("MICROSOFT_CLIENT_ID")?;
format!("https://login.live.com/oauth20_authorize.srf?client_id={client_id}&response_type=code&scope=user.read&state={state}&prompt=select_account&redirect_uri={redirect_uri}")
format!(
"https://login.live.com/oauth20_authorize.srf?client_id={client_id}&response_type=code&scope=user.read&state={state}&prompt=select_account&redirect_uri={redirect_uri}"
)
}
AuthProvider::GitLab => {
let client_id = dotenvy::var("GITLAB_CLIENT_ID")?;
@ -282,7 +287,9 @@ impl AuthProvider {
"https://accounts.google.com/o/oauth2/v2/auth?client_id={}&state={}&scope={}&response_type=code&redirect_uri={}",
client_id,
state,
urlencoding::encode("https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"),
urlencoding::encode(
"https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
),
redirect_uri,
)
}
@ -291,7 +298,9 @@ impl AuthProvider {
"https://steamcommunity.com/openid/login?openid.ns={}&openid.mode={}&openid.return_to={}{}{}&openid.realm={}&openid.identity={}&openid.claimed_id={}",
urlencoding::encode("http://specs.openid.net/auth/2.0"),
"checkid_setup",
redirect_uri, urlencoding::encode("?state="), state,
redirect_uri,
urlencoding::encode("?state="),
state,
self_addr,
"http://specs.openid.net/auth/2.0/identifier_select",
"http://specs.openid.net/auth/2.0/identifier_select",
@ -309,7 +318,9 @@ impl AuthProvider {
format!(
"https://{auth_url}/connect?flowEntry=static&client_id={client_id}&scope={}&response_type=code&redirect_uri={redirect_uri}&state={state}",
urlencoding::encode("openid email address https://uri.paypal.com/services/paypalattributes"),
urlencoding::encode(
"openid email address https://uri.paypal.com/services/paypalattributes"
),
)
}
})
@ -1259,7 +1270,10 @@ pub async fn delete_auth_provider(
send_email(
email,
"Authentication method removed",
&format!("When logging into Modrinth, you can no longer log in using the {} authentication provider.", delete_provider.provider.as_str()),
&format!(
"When logging into Modrinth, you can no longer log in using the {} authentication provider.",
delete_provider.provider.as_str()
),
"If you did not make this change, please contact us immediately through our support channels on Discord or via email (support@modrinth.com).",
None,
)?;
@ -1304,7 +1318,7 @@ pub async fn sign_up_sendy(email: &str) -> Result<(), AuthenticationError> {
#[derive(Deserialize, Validate)]
pub struct NewAccount {
#[validate(length(min = 1, max = 39), regex = "RE_URL_SAFE")]
#[validate(length(min = 1, max = 39), regex(path = *RE_URL_SAFE))]
pub username: String,
#[validate(length(min = 8, max = 256))]
pub password: String,
@ -1349,13 +1363,11 @@ pub async fn create_account_with_password(
let score = zxcvbn::zxcvbn(
&new_account.password,
&[&new_account.username, &new_account.email],
)?;
);
if score.score() < 3 {
if score.score() < Score::Three {
return Err(ApiError::InvalidInput(
if let Some(feedback) =
score.feedback().clone().and_then(|x| x.warning())
{
if let Some(feedback) = score.feedback().and_then(|x| x.warning()) {
format!("Password too weak: {feedback}")
} else {
"Specified password is too weak! Please improve its strength."
@ -1928,7 +1940,15 @@ pub async fn reset_password_begin(
"Reset your password",
"Please visit the following link below to reset your password. If the button does not work, you can copy the link and paste it into your browser.",
"If you did not request for your password to be reset, you can safely ignore this email.",
Some(("Reset password", &format!("{}/{}?flow={}", dotenvy::var("SITE_URL")?, dotenvy::var("SITE_RESET_PASSWORD_PATH")?, flow))),
Some((
"Reset password",
&format!(
"{}/{}?flow={}",
dotenvy::var("SITE_URL")?,
dotenvy::var("SITE_RESET_PASSWORD_PATH")?,
flow
),
)),
)?;
}
}
@ -2012,12 +2032,12 @@ pub async fn change_password(
let score = zxcvbn::zxcvbn(
new_password,
&[&user.username, &user.email.clone().unwrap_or_default()],
)?;
);
if score.score() < 3 {
if score.score() < Score::Three {
return Err(ApiError::InvalidInput(
if let Some(feedback) =
score.feedback().clone().and_then(|x| x.warning())
score.feedback().and_then(|x| x.warning())
{
format!("Password too weak: {feedback}")
} else {
@ -2135,7 +2155,10 @@ pub async fn set_email(
send_email(
user_email,
"Email changed",
&format!("Your email has been updated to {} on your account.", email.email),
&format!(
"Your email has been updated to {} on your account.",
email.email
),
"If you did not make this change, please contact us immediately through our support channels on Discord or via email (support@modrinth.com).",
None,
)?;
@ -2320,6 +2343,14 @@ fn send_email_verify(
"Verify your email",
opener,
"Please visit the following link below to verify your email. If the button does not work, you can copy the link and paste it into your browser. This link expires in 24 hours.",
Some(("Verify email", &format!("{}/{}?flow={}", dotenvy::var("SITE_URL")?, dotenvy::var("SITE_VERIFY_EMAIL_PATH")?, flow))),
Some((
"Verify email",
&format!(
"{}/{}?flow={}",
dotenvy::var("SITE_URL")?,
dotenvy::var("SITE_VERIFY_EMAIL_PATH")?,
flow
),
)),
)
}

View File

@ -3,7 +3,7 @@ use crate::database::redis::RedisPool;
use crate::models::pats::Scopes;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use actix_web::{post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, post, web};
use sqlx::PgPool;
pub fn config(cfg: &mut web::ServiceConfig) {

View File

@ -8,8 +8,8 @@ pub mod session;
pub mod statuses;
use super::v3::oauth_clients;
pub use super::ApiError;
use super::v3::oauth_clients;
use crate::util::cors::default_cors;
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {

View File

@ -5,7 +5,7 @@ use crate::models::projects::ProjectStatus;
use crate::queue::moderation::{ApprovalType, IdentifiedFile, MissingMetadata};
use crate::queue::session::AuthQueue;
use crate::{auth::check_is_moderator_from_headers, models::pats::Scopes};
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::random_base62;
use serde::Deserialize;
use sqlx::PgPool;

View File

@ -6,12 +6,12 @@ use crate::routes::ApiError;
use crate::database::redis::RedisPool;
use actix_web::web::{self, Data};
use actix_web::{delete, get, patch, post, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post};
use chrono::{DateTime, Utc};
use rand::distributions::Alphanumeric;
use rand::Rng;
use rand_chacha::rand_core::SeedableRng;
use rand::distributions::Alphanumeric;
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
use crate::models::pats::{PersonalAccessToken, Scopes};
use crate::queue::session::AuthQueue;

View File

@ -1,7 +1,7 @@
use crate::auth::{get_user_from_headers, AuthenticationError};
use crate::auth::{AuthenticationError, get_user_from_headers};
use crate::database::models::UserId;
use crate::database::models::session_item::Session as DBSession;
use crate::database::models::session_item::SessionBuilder;
use crate::database::models::UserId;
use crate::database::redis::RedisPool;
use crate::models::pats::Scopes;
use crate::models::sessions::Session;
@ -9,8 +9,8 @@ use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::util::env::parse_var;
use actix_web::http::header::AUTHORIZATION;
use actix_web::web::{scope, Data, ServiceConfig};
use actix_web::{delete, get, post, web, HttpRequest, HttpResponse};
use actix_web::web::{Data, ServiceConfig, scope};
use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
use chrono::Utc;
use rand::distributions::Alphanumeric;
use rand::{Rng, SeedableRng};

View File

@ -1,5 +1,5 @@
use crate::auth::validate::get_user_record_from_bearer_token;
use crate::auth::AuthenticationError;
use crate::auth::validate::get_user_record_from_bearer_token;
use crate::database::models::friend_item::FriendItem;
use crate::database::redis::RedisPool;
use crate::models::pats::Scopes;
@ -9,12 +9,12 @@ use crate::queue::socket::{
ActiveSocket, ActiveSockets, SocketId, TunnelSocketType,
};
use crate::routes::ApiError;
use crate::sync::friends::{RedisFriendsMessage, FRIENDS_CHANNEL_NAME};
use crate::sync::friends::{FRIENDS_CHANNEL_NAME, RedisFriendsMessage};
use crate::sync::status::{
get_user_status, push_back_user_expiry, replace_user_status,
};
use actix_web::web::{Data, Payload};
use actix_web::{get, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, get, web};
use actix_ws::Message;
use ariadne::ids::UserId;
use ariadne::networking::message::{
@ -31,7 +31,7 @@ use sqlx::PgPool;
use std::pin::pin;
use std::sync::atomic::Ordering;
use tokio::sync::oneshot::error::TryRecvError;
use tokio::time::{sleep, Duration};
use tokio::time::{Duration, sleep};
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(ws_init);

View File

@ -9,7 +9,7 @@ use crate::models::projects::{ProjectId, VersionId};
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::{auth::get_user_from_headers, database};
use actix_web::{get, route, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, get, route, web};
use sqlx::PgPool;
use std::collections::HashSet;
use yaserde_derive::YaSerialize;

View File

@ -5,7 +5,7 @@ use crate::util::env::parse_strings_from_var;
use actix_cors::Cors;
use actix_files::Files;
use actix_web::http::StatusCode;
use actix_web::{web, HttpResponse};
use actix_web::{HttpResponse, web};
use futures::FutureExt;
pub mod internal;
@ -127,8 +127,6 @@ pub enum ApiError {
ImageParse(#[from] image::ImageError),
#[error("Password Hashing Error: {0}")]
PasswordHashing(#[from] argon2::password_hash::Error),
#[error("Password strength checking error: {0}")]
PasswordStrengthCheck(#[from] zxcvbn::ZxcvbnError),
#[error("{0}")]
Mail(#[from] crate::auth::email::MailError),
#[error("Error while rerouting request: {0}")]
@ -139,7 +137,9 @@ pub enum ApiError {
Io(#[from] std::io::Error),
#[error("Resource not found")]
NotFound,
#[error("You are being rate-limited. Please wait {0} milliseconds. 0/{1} remaining.")]
#[error(
"You are being rate-limited. Please wait {0} milliseconds. 0/{1} remaining."
)]
RateLimitError(u128, u32),
#[error("Error while interacting with payment processor: {0}")]
Stripe(#[from] stripe::StripeError),
@ -168,7 +168,6 @@ impl ApiError {
ApiError::Decoding(..) => "decoding_error",
ApiError::ImageParse(..) => "invalid_image",
ApiError::PasswordHashing(..) => "password_hashing_error",
ApiError::PasswordStrengthCheck(..) => "strength_check_error",
ApiError::Mail(..) => "mail_error",
ApiError::Clickhouse(..) => "clickhouse_error",
ApiError::Reroute(..) => "reroute_error",
@ -206,7 +205,6 @@ impl actix_web::ResponseError for ApiError {
ApiError::Decoding(..) => StatusCode::BAD_REQUEST,
ApiError::ImageParse(..) => StatusCode::BAD_REQUEST,
ApiError::PasswordHashing(..) => StatusCode::INTERNAL_SERVER_ERROR,
ApiError::PasswordStrengthCheck(..) => StatusCode::BAD_REQUEST,
ApiError::Mail(..) => StatusCode::INTERNAL_SERVER_ERROR,
ApiError::Reroute(..) => StatusCode::INTERNAL_SERVER_ERROR,
ApiError::NotFound => StatusCode::NOT_FOUND,

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use actix_web::{get, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, get, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;

View File

@ -4,7 +4,7 @@ use crate::models::v2::projects::LegacyProject;
use crate::queue::session::AuthQueue;
use crate::routes::internal;
use crate::{database::redis::RedisPool, routes::v2_reroute};
use actix_web::{get, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, get, web};
use serde::Deserialize;
use sqlx::PgPool;

View File

@ -3,10 +3,10 @@ use crate::models::ids::NotificationId;
use crate::models::notifications::Notification;
use crate::models::v2::notifications::LegacyNotification;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::routes::v2_reroute;
use crate::routes::v3;
use crate::routes::ApiError;
use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;

View File

@ -13,7 +13,7 @@ use crate::routes::v3::project_creation::{CreateError, NewGalleryItem};
use crate::routes::{v2_reroute, v3};
use actix_multipart::Multipart;
use actix_web::web::Data;
use actix_web::{post, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, post};
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::postgres::PgPool;
@ -47,7 +47,7 @@ struct ProjectCreateData {
pub project_type: String,
#[validate(
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
#[serde(alias = "mod_slug")]
/// The slug of a project, used for vanity URLs
@ -66,8 +66,7 @@ struct ProjectCreateData {
/// The support range for the server project
pub server_side: LegacySideType,
#[validate(length(max = 32))]
#[validate]
#[validate(nested, length(max = 32))]
/// A list of initial versions to upload with the created project
pub initial_versions: Vec<InitialVersionData>,
#[validate(length(max = 3))]
@ -109,7 +108,7 @@ struct ProjectCreateData {
/// An optional link to the project's discord.
pub discord_url: Option<String>,
/// An optional list of all donation links the project has\
#[validate]
#[validate(nested)]
pub donation_urls: Option<Vec<DonationLink>>,
/// An optional boolean. If true, the project will be created as a draft.
@ -118,8 +117,7 @@ struct ProjectCreateData {
/// The license id that the project follows
pub license_id: String,
#[validate(length(max = 64))]
#[validate]
#[validate(nested, length(max = 64))]
/// The multipart names of the gallery items to upload
pub gallery_items: Option<Vec<NewGalleryItem>>,
#[serde(default = "default_requested_status")]

View File

@ -12,9 +12,9 @@ use crate::models::v2::search::LegacySearchResults;
use crate::queue::moderation::AutomatedModerationQueue;
use crate::queue::session::AuthQueue;
use crate::routes::v3::projects::ProjectIds;
use crate::routes::{v2_reroute, v3, ApiError};
use crate::search::{search_for_project, SearchConfig, SearchError};
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use crate::routes::{ApiError, v2_reroute, v3};
use crate::search::{SearchConfig, SearchError, search_for_project};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use std::collections::HashMap;
@ -371,14 +371,14 @@ pub struct EditProject {
length(max = 2048)
)]
pub discord_url: Option<Option<String>>,
#[validate]
#[validate(nested)]
pub donation_urls: Option<Vec<DonationLink>>,
pub license_id: Option<String>,
pub client_side: Option<LegacySideType>,
pub server_side: Option<LegacySideType>,
#[validate(
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub slug: Option<String>,
pub status: Option<ProjectStatus>,
@ -586,11 +586,11 @@ pub struct BulkEditProject {
pub add_additional_categories: Option<Vec<String>>,
pub remove_additional_categories: Option<Vec<String>>,
#[validate]
#[validate(nested)]
pub donation_urls: Option<Vec<DonationLink>>,
#[validate]
#[validate(nested)]
pub add_donation_urls: Option<Vec<DonationLink>>,
#[validate]
#[validate(nested)]
pub remove_donation_urls: Option<Vec<DonationLink>>,
#[serde(

View File

@ -2,8 +2,8 @@ use crate::database::redis::RedisPool;
use crate::models::reports::Report;
use crate::models::v2::reports::LegacyReport;
use crate::queue::session::AuthQueue;
use crate::routes::{v2_reroute, v3, ApiError};
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use crate::routes::{ApiError, v2_reroute, v3};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post, web};
use serde::Deserialize;
use sqlx::PgPool;
use validator::Validate;

View File

@ -1,9 +1,8 @@
use crate::routes::{
v2_reroute,
ApiError, v2_reroute,
v3::{self, statistics::V3Stats},
ApiError,
};
use actix_web::{get, web, HttpResponse};
use actix_web::{HttpResponse, get, web};
use sqlx::PgPool;
pub fn config(cfg: &mut web::ServiceConfig) {

View File

@ -7,7 +7,7 @@ use crate::models::v2::projects::LegacySideType;
use crate::routes::v2_reroute::capitalize_first;
use crate::routes::v3::tags::{LinkPlatformQueryData, LoaderFieldsEnumQuery};
use crate::routes::{v2_reroute, v3};
use actix_web::{get, web, HttpResponse};
use actix_web::{HttpResponse, get, web};
use chrono::{DateTime, Utc};
use itertools::Itertools;
use sqlx::PgPool;

View File

@ -5,8 +5,8 @@ use crate::models::teams::{
use crate::models::users::UserId;
use crate::models::v2::teams::LegacyTeamMember;
use crate::queue::session::AuthQueue;
use crate::routes::{v2_reroute, v3, ApiError};
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use crate::routes::{ApiError, v2_reroute, v3};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post, web};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;

View File

@ -6,8 +6,8 @@ use crate::models::ids::ThreadMessageId;
use crate::models::threads::{MessageBody, Thread, ThreadId};
use crate::models::v2::threads::LegacyThread;
use crate::queue::session::AuthQueue;
use crate::routes::{v2_reroute, v3, ApiError};
use actix_web::{delete, get, post, web, HttpRequest, HttpResponse};
use crate::routes::{ApiError, v2_reroute, v3};
use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
use serde::Deserialize;
use sqlx::PgPool;

View File

@ -7,8 +7,8 @@ use crate::models::v2::notifications::LegacyNotification;
use crate::models::v2::projects::LegacyProject;
use crate::models::v2::user::LegacyUser;
use crate::queue::session::AuthQueue;
use crate::routes::{v2_reroute, v3, ApiError};
use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse};
use crate::routes::{ApiError, v2_reroute, v3};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, web};
use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize};
@ -141,14 +141,14 @@ lazy_static! {
#[derive(Serialize, Deserialize, Validate)]
pub struct EditUser {
#[validate(length(min = 1, max = 39), regex = "RE_URL_SAFE")]
#[validate(length(min = 1, max = 39), regex(path = *RE_URL_SAFE))]
pub username: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "::serde_with::rust::double_option"
)]
#[validate(length(min = 1, max = 64), regex = "RE_URL_SAFE")]
#[validate(length(min = 1, max = 64), regex(path = *RE_URL_SAFE))]
pub name: Option<Option<String>>,
#[serde(
default,

View File

@ -16,7 +16,7 @@ use crate::routes::{v2_reroute, v3};
use actix_multipart::Multipart;
use actix_web::http::header::ContentDisposition;
use actix_web::web::Data;
use actix_web::{post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, post, web};
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::postgres::PgPool;
@ -36,7 +36,7 @@ pub struct InitialVersionData {
pub file_parts: Vec<String>,
#[validate(
length(min = 1, max = 32),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub version_number: String,
#[validate(

View File

@ -5,7 +5,7 @@ use crate::models::v2::projects::{LegacyProject, LegacyVersion};
use crate::queue::session::AuthQueue;
use crate::routes::v3::version_file::HashQuery;
use crate::routes::{v2_reroute, v3};
use actix_web::{delete, get, post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use std::collections::HashMap;

View File

@ -11,7 +11,7 @@ use crate::models::v2::projects::LegacyVersion;
use crate::queue::session::AuthQueue;
use crate::routes::{v2_reroute, v3};
use crate::search::SearchConfig;
use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use validator::Validate;
@ -219,7 +219,7 @@ pub struct EditVersion {
pub name: Option<String>,
#[validate(
length(min = 1, max = 32),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub version_number: Option<String>,
#[validate(length(max = 65536))]

View File

@ -1,18 +1,18 @@
use std::collections::HashMap;
use super::v3::project_creation::CreateError;
use super::ApiError;
use super::v3::project_creation::CreateError;
use crate::models::v2::projects::LegacySideType;
use crate::util::actix::{
generate_multipart, MultipartSegment, MultipartSegmentData,
MultipartSegment, MultipartSegmentData, generate_multipart,
};
use actix_multipart::Multipart;
use actix_web::HttpResponse;
use actix_web::http::header::{
ContentDisposition, HeaderMap, TryIntoHeaderPair,
};
use actix_web::HttpResponse;
use futures::{stream, Future, StreamExt};
use serde_json::{json, Value};
use futures::{Future, StreamExt, stream};
use serde_json::{Value, json};
pub async fn extract_ok_json<T>(
response: HttpResponse,
@ -73,7 +73,7 @@ where
if let Some(field) = multipart.next().await {
let mut field = field?;
let content_disposition = field.content_disposition().clone();
let content_disposition = field.content_disposition().unwrap().clone();
let field_name = content_disposition.get_name().unwrap_or("");
let field_filename = content_disposition.get_filename();
let field_content_type = field.content_type();
@ -100,7 +100,7 @@ where
while let Some(field) = multipart.next().await {
let mut field = field?;
let content_disposition = field.content_disposition().clone();
let content_disposition = field.content_disposition().unwrap().clone();
let field_name = content_disposition.get_name().unwrap_or("");
let field_filename = content_disposition.get_filename();
let field_content_type = field.content_type();

View File

@ -11,12 +11,12 @@ use crate::{
},
queue::session::AuthQueue,
};
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::base62_impl::to_base62;
use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
use sqlx::postgres::types::PgInterval;
use sqlx::PgPool;
use sqlx::postgres::types::PgInterval;
use std::collections::HashMap;
use std::convert::TryInto;

View File

@ -9,14 +9,14 @@ use crate::models::collections::{Collection, CollectionStatus};
use crate::models::ids::{CollectionId, ProjectId};
use crate::models::pats::Scopes;
use crate::queue::session::AuthQueue;
use crate::routes::v3::project_creation::CreateError;
use crate::routes::ApiError;
use crate::routes::v3::project_creation::CreateError;
use crate::util::img::delete_old_images;
use crate::util::routes::read_from_payload;
use crate::util::validate::validation_errors_to_string;
use crate::{database, models};
use actix_web::web::Data;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::base62_impl::parse_base62;
use chrono::Utc;
use itertools::Itertools;
@ -322,8 +322,9 @@ pub async fn collection_edit(
.collect_vec();
let mut validated_project_ids = Vec::new();
for project_id in new_project_ids {
let project =
database::models::Project::get(project_id, &**pool, &redis)
let project = database::models::Project::get(
project_id, &**pool, &redis,
)
.await?
.ok_or_else(|| {
ApiError::InvalidInput(format!(

View File

@ -5,13 +5,13 @@ use crate::models::pats::Scopes;
use crate::models::users::UserFriend;
use crate::queue::session::AuthQueue;
use crate::queue::socket::ActiveSockets;
use crate::routes::ApiError;
use crate::routes::internal::statuses::{
broadcast_friends_message, send_message_to_user,
};
use crate::routes::ApiError;
use crate::sync::friends::RedisFriendsMessage;
use crate::sync::status::get_user_status;
use actix_web::{delete, get, post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
use ariadne::networking::message::ServerToClientMessage;
use chrono::Utc;
use sqlx::PgPool;

View File

@ -16,7 +16,7 @@ use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::util::img::upload_image_optimized;
use crate::util::routes::read_from_payload;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;

View File

@ -1,6 +1,6 @@
pub use super::ApiError;
use crate::util::cors::default_cors;
use actix_web::{web, HttpResponse};
use actix_web::{HttpResponse, web};
use serde_json::json;
pub mod analytics_get;

View File

@ -6,7 +6,7 @@ use crate::models::notifications::Notification;
use crate::models::pats::Scopes;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
@ -45,8 +45,8 @@ pub async fn notifications_get(
.await?
.1;
use database::models::notification_item::Notification as DBNotification;
use database::models::NotificationId as DBNotificationId;
use database::models::notification_item::Notification as DBNotification;
let notification_ids: Vec<DBNotificationId> =
serde_json::from_str::<Vec<NotificationId>>(ids.ids.as_str())?

View File

@ -5,10 +5,10 @@ use crate::{
auth::{checks::ValidateAuthorized, get_user_from_headers},
database::{
models::{
generate_oauth_client_id, generate_oauth_redirect_id,
DatabaseError, OAuthClientId, User, generate_oauth_client_id,
generate_oauth_redirect_id,
oauth_client_authorization_item::OAuthClientAuthorization,
oauth_client_item::{OAuthClient, OAuthRedirectUri},
DatabaseError, OAuthClientId, User,
},
redis::RedisPool,
},
@ -26,14 +26,13 @@ use crate::{
util::routes::read_from_payload,
};
use actix_web::{
delete, get, patch, post,
HttpRequest, HttpResponse, delete, get, patch, post,
web::{self, scope},
HttpRequest, HttpResponse,
};
use ariadne::ids::base62_impl::parse_base62;
use chrono::Utc;
use itertools::Itertools;
use rand::{distributions::Alphanumeric, Rng, SeedableRng};
use rand::{Rng, SeedableRng, distributions::Alphanumeric};
use rand_chacha::ChaCha20Rng;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;

View File

@ -5,7 +5,7 @@ use super::ApiError;
use crate::auth::{filter_visible_projects, get_user_from_headers};
use crate::database::models::team_item::TeamMember;
use crate::database::models::{
generate_organization_id, team_item, Organization,
Organization, generate_organization_id, team_item,
};
use crate::database::redis::RedisPool;
use crate::file_hosting::FileHost;
@ -19,7 +19,7 @@ use crate::util::img::delete_old_images;
use crate::util::routes::read_from_payload;
use crate::util::validate::validation_errors_to_string;
use crate::{database, models};
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::base62_impl::parse_base62;
use futures::TryStreamExt;
use rust_decimal::Decimal;
@ -102,7 +102,7 @@ pub async fn organization_projects_get(
pub struct NewOrganization {
#[validate(
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub slug: String,
// Title of the organization
@ -371,7 +371,7 @@ pub struct OrganizationEdit {
pub description: Option<String>,
#[validate(
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub slug: Option<String>,
#[validate(length(min = 3, max = 64))]

View File

@ -1,17 +1,17 @@
use crate::auth::validate::get_user_record_from_bearer_token;
use crate::auth::{get_user_from_headers, AuthenticationError};
use crate::auth::{AuthenticationError, get_user_from_headers};
use crate::database::models::generate_payout_id;
use crate::database::redis::RedisPool;
use crate::models::ids::PayoutId;
use crate::models::pats::Scopes;
use crate::models::payouts::{PayoutMethodType, PayoutStatus};
use crate::queue::payouts::{make_aditude_request, PayoutsQueue};
use crate::queue::payouts::{PayoutsQueue, make_aditude_request};
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use actix_web::{delete, get, post, web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
use chrono::{DateTime, Datelike, Duration, TimeZone, Utc, Weekday};
use hex::ToHex;
use hmac::{Hmac, Mac, NewMac};
use hmac::{Hmac, Mac};
use reqwest::Method;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
@ -620,7 +620,7 @@ pub async fn create_payout(
PayoutMethodType::Unknown => {
return Err(ApiError::Payments(
"Invalid payment method specified!".to_string(),
))
));
}
};
@ -696,7 +696,7 @@ pub async fn cancel_payout(
PayoutMethodType::Unknown => {
return Err(ApiError::InvalidInput(
"Payout cannot be cancelled!".to_string(),
))
));
}
}

View File

@ -1,10 +1,10 @@
use super::version_creation::{try_create_version_fields, InitialVersionData};
use crate::auth::{get_user_from_headers, AuthenticationError};
use super::version_creation::{InitialVersionData, try_create_version_fields};
use crate::auth::{AuthenticationError, get_user_from_headers};
use crate::database::models::loader_fields::{
Loader, LoaderField, LoaderFieldEnumValue,
};
use crate::database::models::thread_item::ThreadBuilder;
use crate::database::models::{self, image_item, User};
use crate::database::models::{self, User, image_item};
use crate::database::redis::RedisPool;
use crate::file_hosting::{FileHost, FileHostingError};
use crate::models::error::ApiError;
@ -168,7 +168,7 @@ pub struct ProjectCreateData {
pub name: String,
#[validate(
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
#[serde(alias = "mod_slug")]
/// The slug of a project, used for vanity URLs
@ -182,8 +182,7 @@ pub struct ProjectCreateData {
/// A long description of the project, in markdown.
pub description: String,
#[validate(length(max = 32))]
#[validate]
#[validate(nested, length(max = 32))]
/// A list of initial versions to upload with the created project
pub initial_versions: Vec<InitialVersionData>,
#[validate(length(max = 3))]
@ -209,8 +208,7 @@ pub struct ProjectCreateData {
/// The license id that the project follows
pub license_id: String,
#[validate(length(max = 64))]
#[validate]
#[validate(nested, length(max = 64))]
/// The multipart names of the gallery items to upload
pub gallery_items: Option<Vec<NewGalleryItem>>,
#[serde(default = "default_requested_status")]
@ -373,8 +371,7 @@ async fn project_create_inner(
)))
})?;
let content_disposition = field.content_disposition();
let name = content_disposition.get_name().ok_or_else(|| {
let name = field.name().ok_or_else(|| {
CreateError::MissingValueError(String::from("Missing content name"))
})?;
@ -472,7 +469,7 @@ async fn project_create_inner(
}
let result = async {
let content_disposition = field.content_disposition().clone();
let content_disposition = field.content_disposition().unwrap().clone();
let name = content_disposition.get_name().ok_or_else(|| {
CreateError::MissingValueError("Missing content name".to_string())

View File

@ -6,7 +6,7 @@ use crate::auth::{filter_visible_projects, get_user_from_headers};
use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::project_item::{GalleryItem, ModCategory};
use crate::database::models::thread_item::ThreadMessageBuilder;
use crate::database::models::{ids as db_ids, image_item, TeamMember};
use crate::database::models::{TeamMember, ids as db_ids, image_item};
use crate::database::redis::RedisPool;
use crate::database::{self, models as db_models};
use crate::file_hosting::FileHost;
@ -23,12 +23,12 @@ use crate::queue::moderation::AutomatedModerationQueue;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::search::indexing::remove_documents;
use crate::search::{search_for_project, SearchConfig, SearchError};
use crate::search::{SearchConfig, SearchError, search_for_project};
use crate::util::img;
use crate::util::img::{delete_old_images, upload_image_optimized};
use crate::util::routes::read_from_payload;
use crate::util::validate::validation_errors_to_string;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::base62_impl::parse_base62;
use chrono::Utc;
use futures::TryStreamExt;
@ -214,7 +214,7 @@ pub struct EditProject {
pub license_id: Option<String>,
#[validate(
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub slug: Option<String>,
pub status: Option<ProjectStatus>,

View File

@ -14,7 +14,7 @@ use crate::models::threads::{MessageBody, ThreadType};
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::util::img;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::base62_impl::parse_base62;
use chrono::Utc;
use futures::StreamExt;
@ -162,7 +162,7 @@ pub async fn report_create(
return Err(ApiError::InvalidInput(format!(
"Invalid report item type: {}",
new_report.item_type.as_str()
)))
)));
}
}

View File

@ -1,5 +1,5 @@
use crate::routes::ApiError;
use actix_web::{web, HttpResponse};
use actix_web::{HttpResponse, web};
use sqlx::PgPool;
pub fn config(cfg: &mut web::ServiceConfig) {

View File

@ -8,7 +8,7 @@ use crate::database::models::loader_fields::{
Game, Loader, LoaderField, LoaderFieldEnumValue, LoaderFieldType,
};
use crate::database::redis::RedisPool;
use actix_web::{web, HttpResponse};
use actix_web::{HttpResponse, web};
use itertools::Itertools;
use serde_json::Value;
@ -156,7 +156,7 @@ pub async fn loader_fields_list(
"'{}' is not an enumerable field, but an '{}' field.",
query.loader_field,
loader_field.field_type.to_str()
)))
)));
}
};

View File

@ -1,10 +1,10 @@
use crate::auth::checks::is_visible_project;
use crate::auth::get_user_from_headers;
use crate::database::Project;
use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::team_item::TeamAssociationId;
use crate::database::models::{Organization, Team, TeamMember, User};
use crate::database::redis::RedisPool;
use crate::database::Project;
use crate::models::notifications::NotificationBody;
use crate::models::pats::Scopes;
use crate::models::teams::{
@ -13,7 +13,7 @@ use crate::models::teams::{
use crate::models::users::UserId;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
@ -299,7 +299,7 @@ pub async fn teams_get(
.map(|x| x.1)
.ok();
let teams_groups = teams_data.into_iter().group_by(|data| data.team_id.0);
let teams_groups = teams_data.into_iter().chunk_by(|data| data.team_id.0);
let mut teams: Vec<Vec<crate::models::teams::TeamMember>> = vec![];

View File

@ -16,7 +16,7 @@ use crate::models::threads::{MessageBody, Thread, ThreadId, ThreadType};
use crate::models::users::User;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use futures::TryStreamExt;
use serde::Deserialize;
use sqlx::PgPool;

View File

@ -1,13 +1,13 @@
use std::{collections::HashMap, sync::Arc};
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use validator::Validate;
use super::{oauth_clients::get_user_clients, ApiError};
use super::{ApiError, oauth_clients::get_user_clients};
use crate::util::img::delete_old_images;
use crate::{
auth::{filter_visible_projects, get_user_from_headers},
@ -364,7 +364,7 @@ lazy_static! {
#[derive(Serialize, Deserialize, Validate)]
pub struct EditUser {
#[validate(length(min = 1, max = 39), regex = "RE_URL_SAFE")]
#[validate(length(min = 1, max = 39), regex(path = *RE_URL_SAFE))]
pub username: Option<String>,
#[serde(
default,

View File

@ -7,31 +7,33 @@ use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::version_item::{
DependencyBuilder, VersionBuilder, VersionFileBuilder,
};
use crate::database::models::{self, image_item, Organization};
use crate::database::models::{self, Organization, image_item};
use crate::database::redis::RedisPool;
use crate::file_hosting::FileHost;
use crate::models::images::{Image, ImageContext, ImageId};
use crate::models::notifications::NotificationBody;
use crate::models::pack::PackFileHash;
use crate::models::pats::Scopes;
use crate::models::projects::{skip_nulls, DependencyType, ProjectStatus};
use crate::models::projects::{
Dependency, FileType, Loader, ProjectId, Version, VersionFile, VersionId,
VersionStatus, VersionType,
};
use crate::models::projects::{DependencyType, ProjectStatus, skip_nulls};
use crate::models::teams::ProjectPermissions;
use crate::queue::moderation::AutomatedModerationQueue;
use crate::queue::session::AuthQueue;
use crate::util::routes::read_from_field;
use crate::util::validate::validation_errors_to_string;
use crate::validate::{validate_file, ValidationResult};
use crate::validate::{ValidationResult, validate_file};
use actix_multipart::{Field, Multipart};
use actix_web::web::Data;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use chrono::Utc;
use futures::stream::StreamExt;
use hex::ToHex;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use sha1::Digest;
use sqlx::postgres::PgPool;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
@ -50,7 +52,7 @@ pub struct InitialVersionData {
pub file_parts: Vec<String>,
#[validate(
length(min = 1, max = 32),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub version_number: String,
#[validate(
@ -180,7 +182,7 @@ async fn version_create_inner(
}
let result = async {
let content_disposition = field.content_disposition().clone();
let content_disposition = field.content_disposition().unwrap().clone();
let name = content_disposition.get_name().ok_or_else(|| {
CreateError::MissingValueError("Missing content name".to_string())
})?;
@ -692,7 +694,8 @@ async fn upload_file_to_version_inner(
}
let result = async {
let content_disposition = field.content_disposition().clone();
let content_disposition =
field.content_disposition().unwrap().clone();
let name = content_disposition.get_name().ok_or_else(|| {
CreateError::MissingValueError(
"Missing content name".to_string(),
@ -831,7 +834,7 @@ pub async fn upload_file(
"Project file exceeds the maximum of 500MiB. Contact a moderator or admin to request permission to upload larger files."
).await?;
let hash = sha1::Sha1::from(&data).hexdigest();
let hash = sha1::Sha1::digest(&data).encode_hex::<String>();
let exists = sqlx::query!(
"
SELECT EXISTS(SELECT 1 FROM hashes h

View File

@ -8,7 +8,7 @@ use crate::models::projects::VersionType;
use crate::models::teams::ProjectPermissions;
use crate::queue::session::AuthQueue;
use crate::{database, models};
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use dashmap::DashMap;
use futures::TryStreamExt;
use itertools::Itertools;

View File

@ -10,23 +10,23 @@ use crate::database::models::loader_fields::{
self, LoaderField, LoaderFieldEnumValue, VersionField,
};
use crate::database::models::version_item::{DependencyBuilder, LoaderVersion};
use crate::database::models::{image_item, Organization};
use crate::database::models::{Organization, image_item};
use crate::database::redis::RedisPool;
use crate::models;
use crate::models::ids::VersionId;
use crate::models::images::ImageContext;
use crate::models::pats::Scopes;
use crate::models::projects::{skip_nulls, Loader};
use crate::models::projects::{
Dependency, FileType, VersionStatus, VersionType,
};
use crate::models::projects::{Loader, skip_nulls};
use crate::models::teams::ProjectPermissions;
use crate::queue::session::AuthQueue;
use crate::search::indexing::remove_documents;
use crate::search::SearchConfig;
use crate::search::indexing::remove_documents;
use crate::util::img;
use crate::util::validate::validation_errors_to_string;
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web::{HttpRequest, HttpResponse, web};
use ariadne::ids::base62_impl::parse_base62;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
@ -207,7 +207,7 @@ pub struct EditVersion {
pub name: Option<String>,
#[validate(
length(min = 1, max = 32),
regex = "crate::util::validate::RE_URL_SAFE"
regex(path = *crate::util::validate::RE_URL_SAFE)
)]
pub version_number: Option<String>,
#[validate(length(max = 65536))]

View File

@ -1,7 +1,7 @@
use crate::models::error::ApiError;
use crate::models::projects::SearchRequest;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use actix_web::http::StatusCode;
use chrono::{DateTime, Utc};
use itertools::Itertools;
use meilisearch_sdk::client::Client;
@ -252,10 +252,10 @@ pub async fn search_for_project(
serde_json::from_value::<Vec<String>>(facet)
.unwrap_or_default()
} else {
vec![serde_json::from_value::<String>(
facet,
)
.unwrap_or_default()]
vec![
serde_json::from_value::<String>(facet)
.unwrap_or_default(),
]
}
})
.collect_vec()

View File

@ -5,11 +5,12 @@ use crate::file_hosting::FileHost;
use crate::models::images::ImageContext;
use crate::routes::ApiError;
use color_thief::ColorFormat;
use hex::ToHex;
use image::imageops::FilterType;
use image::{
DynamicImage, EncodableLayout, GenericImageView, ImageError,
ImageOutputFormat,
DynamicImage, EncodableLayout, GenericImageView, ImageError, ImageFormat,
};
use sha1::Digest;
use std::io::Cursor;
use webp::Encoder;
@ -57,7 +58,7 @@ pub async fn upload_image_optimized(
let cdn_url = dotenvy::var("CDN_URL")?;
let hash = sha1::Sha1::from(&bytes).hexdigest();
let hash = sha1::Sha1::digest(&bytes).encode_hex::<String>();
let (processed_image, processed_image_ext) = process_image(
bytes.clone(),
content_type,
@ -150,7 +151,7 @@ fn process_image(
// Optimize and compress
let mut output = Vec::new();
img.write_to(&mut Cursor::new(&mut output), ImageOutputFormat::WebP)?;
img.write_to(&mut Cursor::new(&mut output), ImageFormat::WebP)?;
Ok((bytes::Bytes::from(output), "webp".to_string()))
}

View File

@ -2,10 +2,11 @@ use crate::database::redis::RedisPool;
use crate::routes::ApiError;
use crate::util::env::parse_var;
use actix_web::{
Error, ResponseError,
body::{EitherBody, MessageBody},
dev::{ServiceRequest, ServiceResponse},
middleware::Next,
web, Error, ResponseError,
web,
};
use chrono::Utc;
use std::str::FromStr;

View File

@ -1,5 +1,5 @@
use crate::routes::v3::project_creation::CreateError;
use crate::routes::ApiError;
use crate::routes::v3::project_creation::CreateError;
use actix_multipart::Field;
use actix_web::web::Payload;
use bytes::BytesMut;

View File

@ -19,7 +19,7 @@ pub fn validation_errors_to_string(
let map = errors.into_errors();
let key_option = map.keys().next().copied();
let key_option = map.keys().next();
if let Some(field) = key_option {
if let Some(error) = map.get(field) {

View File

@ -1,5 +1,5 @@
use crate::validate::{
filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult,
SupportedGameVersions, ValidationError, ValidationResult, filter_out_packs,
};
use std::io::Cursor;
use zip::ZipArchive;

View File

@ -1,5 +1,5 @@
use crate::validate::{
filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult,
SupportedGameVersions, ValidationError, ValidationResult, filter_out_packs,
};
use chrono::DateTime;
use std::io::Cursor;

View File

@ -1,5 +1,5 @@
use crate::validate::{
filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult,
SupportedGameVersions, ValidationError, ValidationResult, filter_out_packs,
};
use std::io::Cursor;
use zip::ZipArchive;

View File

@ -1,6 +1,6 @@
use crate::database::models::DatabaseError;
use crate::database::models::legacy_loader_fields::MinecraftGameVersion;
use crate::database::models::loader_fields::VersionField;
use crate::database::models::DatabaseError;
use crate::database::redis::RedisPool;
use crate::models::pack::PackFormat;
use crate::models::projects::{FileType, Loader};

View File

@ -90,7 +90,7 @@ impl super::Validator for ModpackValidator {
_ => {
return Err(ValidationError::InvalidInput(
"Invalid pack file path!".into(),
))
));
}
};
}

View File

@ -1,5 +1,5 @@
use crate::validate::{
filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult,
SupportedGameVersions, ValidationError, ValidationResult, filter_out_packs,
};
use std::io::Cursor;
use zip::ZipArchive;

View File

@ -1,5 +1,5 @@
use crate::validate::{
filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult,
SupportedGameVersions, ValidationError, ValidationResult, filter_out_packs,
};
use chrono::DateTime;
use std::io::Cursor;

Some files were not shown because too many files have changed in this diff Show More