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:
parent
6e46317a37
commit
62de07e4e6
3213
Cargo.lock
generated
3213
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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"] }
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
)?;
|
||||
|
@ -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(),
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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" }
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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)]
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>(
|
||||
|
@ -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())
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{ids::*, Organization, Project};
|
||||
use super::{Organization, Project, ids::*};
|
||||
use crate::{
|
||||
database::redis::RedisPool,
|
||||
models::teams::{OrganizationPermissions, ProjectPermissions},
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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)?;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -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::{
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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((
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use actix_web::{get, HttpResponse};
|
||||
use actix_web::{HttpResponse, get};
|
||||
use serde_json::json;
|
||||
|
||||
#[get("/")]
|
||||
|
@ -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() {
|
||||
|
@ -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")?
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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")]
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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))]
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())?
|
||||
|
@ -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;
|
||||
|
@ -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))]
|
||||
|
@ -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(),
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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>,
|
||||
|
@ -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()
|
||||
)))
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
)))
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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![];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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))]
|
||||
|
@ -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()
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -90,7 +90,7 @@ impl super::Validator for ModpackValidator {
|
||||
_ => {
|
||||
return Err(ValidationError::InvalidInput(
|
||||
"Invalid pack file path!".into(),
|
||||
))
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user