forked from didirus/AstralRinth
Perses finale (#558)
* Move v2 routes to v2 module * Remove v1 routes and make it run * Make config declaration consistent, add v3 module * Readd API v1 msgs * Fix imports
This commit is contained in:
@@ -366,12 +366,9 @@ async fn main() -> std::io::Result<()> {
|
||||
.app_data(web::Data::new(payouts_queue.clone()))
|
||||
.app_data(web::Data::new(ip_salt.clone()))
|
||||
.wrap(sentry_actix::Sentry::new())
|
||||
.configure(routes::v1_config)
|
||||
.configure(routes::v2_config)
|
||||
.service(routes::index_get)
|
||||
.service(routes::health_get)
|
||||
.service(web::scope("maven").configure(routes::maven_config))
|
||||
.service(web::scope("updates").configure(routes::updates))
|
||||
.configure(routes::root_config)
|
||||
.configure(routes::v2::config)
|
||||
.configure(routes::v3::config)
|
||||
.default_service(web::get().to(routes::not_found))
|
||||
})
|
||||
.bind(dotenvy::var("BIND_ADDR").unwrap())?
|
||||
|
||||
@@ -9,6 +9,13 @@ use sqlx::PgPool;
|
||||
use std::collections::HashSet;
|
||||
use yaserde_derive::YaSerialize;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(maven_metadata);
|
||||
cfg.service(version_file_sha512);
|
||||
cfg.service(version_file_sha1);
|
||||
cfg.service(version_file);
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, YaSerialize)]
|
||||
#[yaserde(root = "metadata", rename = "metadata")]
|
||||
pub struct Metadata {
|
||||
@@ -18,6 +25,7 @@ pub struct Metadata {
|
||||
artifact_id: String,
|
||||
versioning: Versioning,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, YaSerialize)]
|
||||
#[yaserde(rename = "versioning")]
|
||||
pub struct Versioning {
|
||||
@@ -27,12 +35,14 @@ pub struct Versioning {
|
||||
#[yaserde(rename = "lastUpdated")]
|
||||
last_updated: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, YaSerialize)]
|
||||
#[yaserde(rename = "versions")]
|
||||
pub struct Versions {
|
||||
#[yaserde(rename = "version")]
|
||||
versions: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, YaSerialize)]
|
||||
#[yaserde(rename = "project", namespace = "http://maven.apache.org/POM/4.0.0")]
|
||||
pub struct MavenPom {
|
||||
|
||||
@@ -1,200 +1,34 @@
|
||||
mod v1;
|
||||
pub use v1::v1_config;
|
||||
use crate::file_hosting::FileHostingError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{web, HttpResponse};
|
||||
use futures::FutureExt;
|
||||
|
||||
pub mod v2;
|
||||
pub mod v3;
|
||||
|
||||
mod admin;
|
||||
mod auth;
|
||||
mod health;
|
||||
mod index;
|
||||
mod maven;
|
||||
mod midas;
|
||||
mod moderation;
|
||||
mod not_found;
|
||||
mod notifications;
|
||||
pub(crate) mod project_creation;
|
||||
mod projects;
|
||||
mod reports;
|
||||
mod statistics;
|
||||
mod tags;
|
||||
mod teams;
|
||||
mod updates;
|
||||
mod users;
|
||||
mod version_creation;
|
||||
mod version_file;
|
||||
mod versions;
|
||||
|
||||
pub use auth::config as auth_config;
|
||||
pub use tags::config as tags_config;
|
||||
|
||||
pub use self::health::health_get;
|
||||
pub use self::index::index_get;
|
||||
pub use self::not_found::not_found;
|
||||
use crate::file_hosting::FileHostingError;
|
||||
use actix_web::web;
|
||||
use image::ImageError;
|
||||
|
||||
pub fn v2_config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn root_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(index::index_get);
|
||||
cfg.service(health::health_get);
|
||||
cfg.service(web::scope("maven").configure(maven::config));
|
||||
cfg.service(web::scope("updates").configure(updates::config));
|
||||
cfg.service(
|
||||
web::scope("v2")
|
||||
.configure(auth_config)
|
||||
.configure(tags_config)
|
||||
.configure(projects_config)
|
||||
.configure(versions_config)
|
||||
.configure(teams_config)
|
||||
.configure(users_config)
|
||||
.configure(moderation_config)
|
||||
.configure(reports_config)
|
||||
.configure(notifications_config)
|
||||
.configure(statistics_config)
|
||||
.configure(admin_config)
|
||||
.configure(midas_config),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn projects_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(projects::project_search);
|
||||
cfg.service(projects::projects_get);
|
||||
cfg.service(projects::projects_edit);
|
||||
cfg.service(projects::random_projects_get);
|
||||
cfg.service(project_creation::project_create);
|
||||
|
||||
cfg.service(
|
||||
web::scope("project")
|
||||
.service(projects::project_get)
|
||||
.service(projects::project_get_check)
|
||||
.service(projects::project_delete)
|
||||
.service(projects::project_edit)
|
||||
.service(projects::project_icon_edit)
|
||||
.service(projects::delete_project_icon)
|
||||
.service(projects::add_gallery_item)
|
||||
.service(projects::edit_gallery_item)
|
||||
.service(projects::delete_gallery_item)
|
||||
.service(projects::project_follow)
|
||||
.service(projects::project_unfollow)
|
||||
.service(projects::project_schedule)
|
||||
.service(teams::team_members_get_project)
|
||||
.service(
|
||||
web::scope("{project_id}")
|
||||
.service(versions::version_list)
|
||||
.service(projects::dependency_list)
|
||||
.service(versions::version_project_get),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn maven_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(maven::maven_metadata);
|
||||
cfg.service(maven::version_file_sha512);
|
||||
cfg.service(maven::version_file_sha1);
|
||||
cfg.service(maven::version_file);
|
||||
}
|
||||
|
||||
pub fn updates(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(updates::forge_updates);
|
||||
}
|
||||
|
||||
pub fn versions_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(versions::versions_get);
|
||||
cfg.service(version_creation::version_create);
|
||||
cfg.service(
|
||||
web::scope("version")
|
||||
.service(versions::version_get)
|
||||
.service(versions::version_delete)
|
||||
.service(version_creation::upload_file_to_version)
|
||||
.service(versions::version_edit)
|
||||
.service(versions::version_schedule),
|
||||
);
|
||||
cfg.service(
|
||||
web::scope("version_file")
|
||||
.service(version_file::delete_file)
|
||||
.service(version_file::get_version_from_hash)
|
||||
.service(version_file::download_version)
|
||||
.service(version_file::get_update_from_hash),
|
||||
);
|
||||
|
||||
cfg.service(
|
||||
web::scope("version_files")
|
||||
.service(version_file::get_versions_from_hashes)
|
||||
.service(version_file::download_files)
|
||||
.service(version_file::update_files),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn users_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(users::user_auth_get);
|
||||
|
||||
cfg.service(users::users_get);
|
||||
cfg.service(
|
||||
web::scope("user")
|
||||
.service(users::user_get)
|
||||
.service(users::projects_list)
|
||||
.service(users::user_delete)
|
||||
.service(users::user_edit)
|
||||
.service(users::user_icon_edit)
|
||||
.service(users::user_notifications)
|
||||
.service(users::user_follows)
|
||||
.service(users::user_payouts)
|
||||
.service(users::user_payouts_request),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn teams_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(teams::teams_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("team")
|
||||
.service(teams::team_members_get)
|
||||
.service(teams::edit_team_member)
|
||||
.service(teams::transfer_ownership)
|
||||
.service(teams::add_team_member)
|
||||
.service(teams::join_team)
|
||||
.service(teams::remove_team_member),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn notifications_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(notifications::notifications_get);
|
||||
cfg.service(notifications::notifications_delete);
|
||||
|
||||
cfg.service(
|
||||
web::scope("notification")
|
||||
.service(notifications::notification_get)
|
||||
.service(notifications::notification_delete),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn moderation_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("moderation")
|
||||
.service(moderation::get_projects)
|
||||
.service(moderation::ban_user)
|
||||
.service(moderation::unban_user),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn reports_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(reports::reports);
|
||||
cfg.service(reports::report_create);
|
||||
cfg.service(reports::delete_report);
|
||||
}
|
||||
|
||||
pub fn statistics_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(statistics::get_stats);
|
||||
}
|
||||
|
||||
pub fn admin_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("admin")
|
||||
.service(admin::count_download)
|
||||
.service(admin::process_payout),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn midas_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("midas")
|
||||
.service(midas::init_checkout)
|
||||
.service(midas::init_customer_portal)
|
||||
.service(midas::handle_stripe_webhook),
|
||||
web::scope("api/v1").wrap_fn(|req, _srv| {
|
||||
async {
|
||||
Ok(req.into_response(
|
||||
HttpResponse::Gone()
|
||||
.content_type("application/json")
|
||||
.body(r#"{"error":"api_deprecated","description":"You are using an application that uses an outdated version of Modrinth's API. Please either update it or switch to another application. For developers: https://docs.modrinth.com/docs/migrations/v1-to-v2/"}"#)
|
||||
))
|
||||
}.boxed_local()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -235,65 +69,35 @@ pub enum ApiError {
|
||||
#[error("Error while decoding Base62: {0}")]
|
||||
Decoding(#[from] crate::models::ids::DecodingError),
|
||||
#[error("Image Parsing Error: {0}")]
|
||||
ImageError(#[from] ImageError),
|
||||
ImageError(#[from] image::ImageError),
|
||||
}
|
||||
|
||||
impl actix_web::ResponseError for ApiError {
|
||||
fn status_code(&self) -> actix_web::http::StatusCode {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
ApiError::Env(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::Database(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::SqlxDatabase(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::Authentication(..) => {
|
||||
actix_web::http::StatusCode::UNAUTHORIZED
|
||||
}
|
||||
ApiError::CustomAuthentication(..) => {
|
||||
actix_web::http::StatusCode::UNAUTHORIZED
|
||||
}
|
||||
ApiError::Xml(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::Json(..) => actix_web::http::StatusCode::BAD_REQUEST,
|
||||
ApiError::Search(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::Indexing(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::FileHosting(..) => {
|
||||
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ApiError::InvalidInput(..) => {
|
||||
actix_web::http::StatusCode::BAD_REQUEST
|
||||
}
|
||||
ApiError::Validation(..) => {
|
||||
actix_web::http::StatusCode::BAD_REQUEST
|
||||
}
|
||||
ApiError::Analytics(..) => {
|
||||
actix_web::http::StatusCode::FAILED_DEPENDENCY
|
||||
}
|
||||
ApiError::Crypto(..) => actix_web::http::StatusCode::FORBIDDEN,
|
||||
ApiError::Payments(..) => {
|
||||
actix_web::http::StatusCode::FAILED_DEPENDENCY
|
||||
}
|
||||
ApiError::DiscordError(..) => {
|
||||
actix_web::http::StatusCode::FAILED_DEPENDENCY
|
||||
}
|
||||
ApiError::Decoding(..) => actix_web::http::StatusCode::BAD_REQUEST,
|
||||
ApiError::ImageError(..) => {
|
||||
actix_web::http::StatusCode::BAD_REQUEST
|
||||
}
|
||||
ApiError::Env(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::Database(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::SqlxDatabase(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::Authentication(..) => StatusCode::UNAUTHORIZED,
|
||||
ApiError::CustomAuthentication(..) => StatusCode::UNAUTHORIZED,
|
||||
ApiError::Xml(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::Json(..) => StatusCode::BAD_REQUEST,
|
||||
ApiError::Search(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::Indexing(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::FileHosting(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiError::InvalidInput(..) => StatusCode::BAD_REQUEST,
|
||||
ApiError::Validation(..) => StatusCode::BAD_REQUEST,
|
||||
ApiError::Analytics(..) => StatusCode::FAILED_DEPENDENCY,
|
||||
ApiError::Crypto(..) => StatusCode::FORBIDDEN,
|
||||
ApiError::Payments(..) => StatusCode::FAILED_DEPENDENCY,
|
||||
ApiError::DiscordError(..) => StatusCode::FAILED_DEPENDENCY,
|
||||
ApiError::Decoding(..) => StatusCode::BAD_REQUEST,
|
||||
ApiError::ImageError(..) => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> actix_web::HttpResponse {
|
||||
actix_web::HttpResponse::build(self.status_code()).json(
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(self.status_code()).json(
|
||||
crate::models::error::ApiError {
|
||||
error: match self {
|
||||
ApiError::Env(..) => "environment_error",
|
||||
|
||||
@@ -12,6 +12,10 @@ use crate::util::auth::{
|
||||
|
||||
use super::ApiError;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(forge_updates);
|
||||
}
|
||||
|
||||
#[get("{id}/forge_updates.json")]
|
||||
pub async fn forge_updates(
|
||||
req: HttpRequest,
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
use actix_web::{dev::Service, http::Method, web, HttpResponse};
|
||||
use chrono::{Timelike, Utc};
|
||||
use futures::FutureExt;
|
||||
|
||||
mod mods;
|
||||
mod tags;
|
||||
mod teams;
|
||||
mod users;
|
||||
mod versions;
|
||||
|
||||
pub fn v1_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("api/v1")
|
||||
.wrap_fn(|req, srv| {
|
||||
let time = Utc::now();
|
||||
|
||||
if req.method() == Method::GET && time.hour12().1 < 6 && time.minute() % 10 < 5 {
|
||||
srv.call(req).boxed_local()
|
||||
} else {
|
||||
async {
|
||||
Ok(
|
||||
req.into_response(
|
||||
HttpResponse::Gone()
|
||||
.content_type("application/json")
|
||||
.body(r#"{"error":"api_deprecated","description":"You are using an application that uses an outdated version of Modrinth's API. Please either update it or switch to another application. For developers: https://docs.modrinth.com/docs/migrations/v1-to-v2/"}"#)
|
||||
)
|
||||
)
|
||||
}.boxed_local()
|
||||
}
|
||||
})
|
||||
.configure(tags_config)
|
||||
.configure(mods_config)
|
||||
.configure(versions_config)
|
||||
.configure(teams_config)
|
||||
.configure(users_config)
|
||||
.configure(notifications_config),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn tags_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("tag")
|
||||
.service(tags::category_list)
|
||||
.service(tags::loader_list)
|
||||
.service(tags::game_version_list)
|
||||
.service(super::tags::license_list)
|
||||
.service(super::tags::report_type_list),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn mods_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(mods::mod_search);
|
||||
cfg.service(mods::mods_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("mod")
|
||||
.service(mods::mod_get)
|
||||
.service(web::scope("{mod_id}").service(versions::version_list)),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn versions_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(versions::versions_get);
|
||||
cfg.service(web::scope("version").service(versions::version_get));
|
||||
cfg.service(
|
||||
web::scope("version_file")
|
||||
.service(super::version_file::get_version_from_hash),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn users_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(super::users::user_auth_get);
|
||||
|
||||
cfg.service(super::users::users_get);
|
||||
cfg.service(
|
||||
web::scope("user")
|
||||
.service(super::users::user_get)
|
||||
.service(users::mods_list)
|
||||
.service(super::users::user_notifications)
|
||||
.service(users::user_follows),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn teams_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(web::scope("team").service(teams::team_members_get));
|
||||
}
|
||||
|
||||
pub fn notifications_config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(super::notifications::notifications_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("notification")
|
||||
.service(super::notifications::notification_get),
|
||||
);
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
use crate::models::projects::SearchRequest;
|
||||
use crate::routes::projects::ProjectIds;
|
||||
use crate::routes::ApiError;
|
||||
use crate::search::{search_for_project, SearchConfig, SearchError};
|
||||
use crate::util::auth::{get_user_from_headers, is_authorized};
|
||||
use crate::{database, models};
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ResultSearchMod {
|
||||
pub mod_id: String,
|
||||
pub slug: Option<String>,
|
||||
pub author: String,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub categories: Vec<String>,
|
||||
pub versions: Vec<String>,
|
||||
pub downloads: i32,
|
||||
pub follows: i32,
|
||||
pub page_url: String,
|
||||
pub icon_url: String,
|
||||
pub author_url: String,
|
||||
pub date_created: String,
|
||||
pub date_modified: String,
|
||||
pub latest_version: String,
|
||||
pub license: String,
|
||||
pub client_side: String,
|
||||
pub server_side: String,
|
||||
pub host: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SearchResults {
|
||||
pub hits: Vec<ResultSearchMod>,
|
||||
pub offset: usize,
|
||||
pub limit: usize,
|
||||
pub total_hits: usize,
|
||||
}
|
||||
|
||||
#[get("mod")]
|
||||
pub async fn mod_search(
|
||||
web::Query(info): web::Query<SearchRequest>,
|
||||
config: web::Data<SearchConfig>,
|
||||
) -> Result<HttpResponse, SearchError> {
|
||||
let results = search_for_project(&info, &config).await?;
|
||||
Ok(HttpResponse::Ok().json(SearchResults {
|
||||
hits: results
|
||||
.hits
|
||||
.into_iter()
|
||||
.map(|x| ResultSearchMod {
|
||||
mod_id: format!("local-{}", x.project_id),
|
||||
slug: x.slug,
|
||||
author: x.author.clone(),
|
||||
title: format!("[STOP USING API v1] {}", x.title),
|
||||
description: format!("[STOP USING API v1] {}", x.description),
|
||||
categories: x.categories,
|
||||
versions: x.versions,
|
||||
downloads: x.downloads,
|
||||
follows: x.follows,
|
||||
page_url: format!("https://modrinth.com/mod/{}", x.project_id),
|
||||
icon_url: x.icon_url,
|
||||
author_url: format!("https://modrinth.com/user/{}", x.author),
|
||||
date_created: x.date_created,
|
||||
date_modified: x.date_modified,
|
||||
latest_version: x.latest_version,
|
||||
license: x.license,
|
||||
client_side: x.client_side,
|
||||
server_side: x.server_side,
|
||||
host: "modrinth".to_string(),
|
||||
})
|
||||
.collect(),
|
||||
offset: results.offset,
|
||||
limit: results.limit,
|
||||
total_hits: results.total_hits,
|
||||
}))
|
||||
}
|
||||
|
||||
#[get("{id}")]
|
||||
pub async fn mod_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let string = info.into_inner().0;
|
||||
|
||||
let project_data =
|
||||
database::models::Project::get_full_from_slug_or_project_id(
|
||||
&string, &**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||
|
||||
if let Some(mut data) = project_data {
|
||||
if is_authorized(&data.inner, &user_option, &pool).await? {
|
||||
data.inner.title =
|
||||
format!("[STOP USING API v1] {}", data.inner.title);
|
||||
data.inner.description =
|
||||
format!("[STOP USING API v1] {}", data.inner.description);
|
||||
data.inner.body =
|
||||
format!("# STOP USING API v1 - whatever application you're using right now is likely deprecated or abandoned\n{}", data.inner.body);
|
||||
return Ok(
|
||||
HttpResponse::Ok().json(models::projects::Project::from(data))
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(HttpResponse::NotFound().body(""))
|
||||
}
|
||||
|
||||
#[get("mods")]
|
||||
pub async fn mods_get(
|
||||
req: HttpRequest,
|
||||
ids: web::Query<ProjectIds>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let project_ids: Vec<database::models::ids::ProjectId> =
|
||||
serde_json::from_str::<Vec<models::ids::ProjectId>>(&ids.ids)?
|
||||
.into_iter()
|
||||
.map(|x| x.into())
|
||||
.collect();
|
||||
|
||||
let projects_data =
|
||||
database::models::Project::get_many_full(&project_ids, &**pool).await?;
|
||||
|
||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||
|
||||
let mut projects = Vec::with_capacity(projects_data.len());
|
||||
|
||||
// can't use `map` and `collect` here since `is_authorized` must be async
|
||||
for mut proj in projects_data {
|
||||
if is_authorized(&proj.inner, &user_option, &pool).await? {
|
||||
proj.inner.title =
|
||||
format!("[STOP USING API v1] {}", proj.inner.title);
|
||||
proj.inner.description =
|
||||
format!("[STOP USING API v1] {}", proj.inner.description);
|
||||
proj.inner.body =
|
||||
format!("# STOP USING API v1 - whatever application you're using right now is likely deprecated or abandoned\n{}", proj.inner.body);
|
||||
projects.push(crate::models::projects::Project::from(proj))
|
||||
}
|
||||
}
|
||||
Ok(HttpResponse::Ok().json(projects))
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
use crate::database::models::categories::{Category, GameVersion, Loader};
|
||||
use crate::routes::ApiError;
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[get("category")]
|
||||
pub async fn category_list(
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results = Category::list(&**pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|x| &*x.project_type == "mod")
|
||||
.map(|x| x.category)
|
||||
.collect::<Vec<String>>();
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
|
||||
#[get("loader")]
|
||||
pub async fn loader_list(
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let results = Loader::list(&**pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|x| x.supported_project_types.contains(&"mod".to_string()))
|
||||
.map(|x| x.loader)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct GameVersionQueryData {
|
||||
#[serde(rename = "type")]
|
||||
type_: Option<String>,
|
||||
major: Option<bool>,
|
||||
}
|
||||
|
||||
#[get("game_version")]
|
||||
pub async fn game_version_list(
|
||||
pool: web::Data<PgPool>,
|
||||
query: web::Query<GameVersionQueryData>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
if query.type_.is_some() || query.major.is_some() {
|
||||
let results = GameVersion::list_filter(
|
||||
query.type_.as_deref(),
|
||||
query.major,
|
||||
&**pool,
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| x.version)
|
||||
.collect::<Vec<String>>();
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
} else {
|
||||
let results = GameVersion::list(&**pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| x.version)
|
||||
.collect::<Vec<String>>();
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
use crate::models::teams::{Permissions, TeamId};
|
||||
use crate::models::users::UserId;
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::auth::get_user_from_headers;
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
|
||||
/// A member of a team
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct TeamMember {
|
||||
/// The ID of the team this team member is a member of
|
||||
pub team_id: TeamId,
|
||||
/// The ID of the user associated with the member
|
||||
pub user_id: UserId,
|
||||
/// The role of the user in the team
|
||||
pub role: String,
|
||||
/// A bitset containing the user's permissions in this team
|
||||
pub permissions: Option<Permissions>,
|
||||
/// Whether the user has joined the team or is just invited to it
|
||||
pub accepted: bool,
|
||||
}
|
||||
|
||||
#[get("{id}/members")]
|
||||
pub async fn team_members_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let id = info.into_inner().0;
|
||||
let members_data =
|
||||
crate::database::models::TeamMember::get_from_team(id.into(), &**pool)
|
||||
.await?;
|
||||
|
||||
let current_user = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||
|
||||
if let Some(user) = current_user {
|
||||
let team_member =
|
||||
crate::database::models::TeamMember::get_from_user_id(
|
||||
id.into(),
|
||||
user.id.into(),
|
||||
&**pool,
|
||||
)
|
||||
.await
|
||||
.map_err(ApiError::Database)?;
|
||||
|
||||
if team_member.is_some() {
|
||||
let team_members: Vec<TeamMember> = members_data
|
||||
.into_iter()
|
||||
.map(|data| TeamMember {
|
||||
team_id: id,
|
||||
user_id: data.user_id.into(),
|
||||
role: data.role,
|
||||
permissions: Some(data.permissions),
|
||||
accepted: data.accepted,
|
||||
})
|
||||
.collect();
|
||||
|
||||
return Ok(HttpResponse::Ok().json(team_members));
|
||||
}
|
||||
}
|
||||
|
||||
let mut team_members: Vec<TeamMember> = Vec::new();
|
||||
|
||||
for team_member in members_data {
|
||||
if team_member.accepted {
|
||||
team_members.push(TeamMember {
|
||||
team_id: id,
|
||||
user_id: team_member.user_id.into(),
|
||||
role: team_member.role,
|
||||
permissions: None,
|
||||
accepted: team_member.accepted,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json(team_members))
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
use crate::database::models::User;
|
||||
use crate::models::ids::UserId;
|
||||
use crate::models::projects::ProjectId;
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::auth::get_user_from_headers;
|
||||
use actix_web::web;
|
||||
use actix_web::{get, HttpRequest, HttpResponse};
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[get("{user_id}/mods")]
|
||||
pub async fn mods_list(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let user = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||
|
||||
let id_option = crate::database::models::User::get_id_from_username_or_id(
|
||||
&info.into_inner().0,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(id) = id_option {
|
||||
let user_id: UserId = id.into();
|
||||
|
||||
let can_view_private = user
|
||||
.map(|y| y.role.is_mod() || y.id == user_id)
|
||||
.unwrap_or(false);
|
||||
|
||||
let project_data = User::get_projects(id, &**pool).await?;
|
||||
|
||||
let response: Vec<_> =
|
||||
crate::database::Project::get_many(&project_data, &**pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|x| can_view_private || x.status.is_approved())
|
||||
.map(|x| x.id.into())
|
||||
.collect::<Vec<ProjectId>>();
|
||||
|
||||
Ok(HttpResponse::Ok().json(response))
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().body(""))
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}/follows")]
|
||||
pub async fn user_follows(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let user = get_user_from_headers(req.headers(), &**pool).await?;
|
||||
let id_option = crate::database::models::User::get_id_from_username_or_id(
|
||||
&info.into_inner().0,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(id) = id_option {
|
||||
if !user.role.is_admin() && user.id != id.into() {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to see the projects this user follows!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
use futures::TryStreamExt;
|
||||
|
||||
let projects: Vec<ProjectId> = sqlx::query!(
|
||||
"
|
||||
SELECT mf.mod_id FROM mod_follows mf
|
||||
WHERE mf.follower_id = $1
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.fetch_many(&**pool)
|
||||
.try_filter_map(|e| async {
|
||||
Ok(e.right().map(|m| ProjectId(m.mod_id as u64)))
|
||||
})
|
||||
.try_collect::<Vec<ProjectId>>()
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(projects))
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().body(""))
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
use crate::database;
|
||||
use crate::models::ids::{ProjectId, UserId, VersionId};
|
||||
use crate::models::projects::{
|
||||
Dependency, GameVersion, Loader, Version, VersionFile, VersionType,
|
||||
};
|
||||
use crate::routes::versions::{VersionIds, VersionListFilters};
|
||||
use crate::routes::ApiError;
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
|
||||
/// A specific version of a mod
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LegacyVersion {
|
||||
pub id: VersionId,
|
||||
pub mod_id: ProjectId,
|
||||
pub author_id: UserId,
|
||||
pub featured: bool,
|
||||
pub name: String,
|
||||
pub version_number: String,
|
||||
pub changelog: String,
|
||||
pub changelog_url: Option<String>,
|
||||
pub date_published: DateTime<Utc>,
|
||||
pub downloads: u32,
|
||||
pub version_type: VersionType,
|
||||
pub files: Vec<VersionFile>,
|
||||
pub dependencies: Vec<Dependency>,
|
||||
pub game_versions: Vec<GameVersion>,
|
||||
pub loaders: Vec<Loader>,
|
||||
}
|
||||
|
||||
fn convert_to_legacy(version: Version) -> LegacyVersion {
|
||||
LegacyVersion {
|
||||
id: version.id,
|
||||
mod_id: version.project_id,
|
||||
author_id: version.author_id,
|
||||
featured: version.featured,
|
||||
name: format!("[STOP USING API v1] {}", version.name),
|
||||
version_number: version.version_number,
|
||||
changelog: format!("# STOP USING API v1 - whatever application you're using right now is likely deprecated or abandoned\n{}", version.changelog),
|
||||
changelog_url: None,
|
||||
date_published: version.date_published,
|
||||
downloads: version.downloads,
|
||||
version_type: version.version_type,
|
||||
files: version.files,
|
||||
dependencies: version.dependencies,
|
||||
game_versions: version.game_versions,
|
||||
loaders: version.loaders,
|
||||
}
|
||||
}
|
||||
|
||||
#[get("version")]
|
||||
pub async fn version_list(
|
||||
info: web::Path<(String,)>,
|
||||
web::Query(filters): web::Query<VersionListFilters>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let string = info.into_inner().0;
|
||||
|
||||
let result = database::models::Project::get_from_slug_or_project_id(
|
||||
&string, &**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(project) = result {
|
||||
let id = project.id;
|
||||
|
||||
let version_ids = database::models::Version::get_project_versions(
|
||||
id,
|
||||
filters
|
||||
.game_versions
|
||||
.as_ref()
|
||||
.map(|x| serde_json::from_str(x).unwrap_or_default()),
|
||||
filters
|
||||
.loaders
|
||||
.as_ref()
|
||||
.map(|x| serde_json::from_str(x).unwrap_or_default()),
|
||||
filters.version_type,
|
||||
filters.limit,
|
||||
filters.offset,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut versions =
|
||||
database::models::Version::get_many_full(&version_ids, &**pool)
|
||||
.await?;
|
||||
|
||||
let mut response = versions
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|version| {
|
||||
filters
|
||||
.featured
|
||||
.map(|featured| featured == version.inner.featured)
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(Version::from)
|
||||
.map(convert_to_legacy)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
versions.sort_by(|a, b| {
|
||||
b.inner.date_published.cmp(&a.inner.date_published)
|
||||
});
|
||||
|
||||
// Attempt to populate versions with "auto featured" versions
|
||||
if response.is_empty()
|
||||
&& !versions.is_empty()
|
||||
&& filters.featured.unwrap_or(false)
|
||||
{
|
||||
let loaders =
|
||||
database::models::categories::Loader::list(&**pool).await?;
|
||||
let game_versions =
|
||||
database::models::categories::GameVersion::list_filter(
|
||||
None,
|
||||
Some(true),
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut joined_filters = Vec::new();
|
||||
for game_version in &game_versions {
|
||||
for loader in &loaders {
|
||||
joined_filters.push((game_version, loader))
|
||||
}
|
||||
}
|
||||
|
||||
joined_filters.into_iter().for_each(|filter| {
|
||||
versions
|
||||
.iter()
|
||||
.find(|version| {
|
||||
version.game_versions.contains(&filter.0.version)
|
||||
&& version.loaders.contains(&filter.1.loader)
|
||||
})
|
||||
.map(|version| {
|
||||
response.push(convert_to_legacy(Version::from(
|
||||
version.clone(),
|
||||
)))
|
||||
})
|
||||
.unwrap_or(());
|
||||
});
|
||||
|
||||
if response.is_empty() {
|
||||
versions.into_iter().for_each(|version| {
|
||||
response.push(convert_to_legacy(Version::from(version)))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
response.sort_by(|a, b| b.date_published.cmp(&a.date_published));
|
||||
response.dedup_by(|a, b| a.id == b.id);
|
||||
|
||||
Ok(HttpResponse::Ok().json(response))
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().body(""))
|
||||
}
|
||||
}
|
||||
|
||||
#[get("versions")]
|
||||
pub async fn versions_get(
|
||||
ids: web::Query<VersionIds>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let version_ids = serde_json::from_str::<Vec<VersionId>>(&ids.ids)?
|
||||
.into_iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<database::models::VersionId>>();
|
||||
let versions_data =
|
||||
database::models::Version::get_many_full(&version_ids, &**pool).await?;
|
||||
|
||||
let mut versions = Vec::new();
|
||||
|
||||
for version_data in versions_data {
|
||||
versions.push(convert_to_legacy(Version::from(version_data)));
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json(versions))
|
||||
}
|
||||
|
||||
#[get("{version_id}")]
|
||||
pub async fn version_get(
|
||||
info: web::Path<(VersionId,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let id = info.into_inner().0;
|
||||
let version_data =
|
||||
database::models::Version::get_full(id.into(), &**pool).await?;
|
||||
|
||||
if let Some(data) = version_data {
|
||||
Ok(HttpResponse::Ok().json(convert_to_legacy(Version::from(data))))
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().body(""))
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,14 @@ use sqlx::PgPool;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("admin")
|
||||
.service(count_download)
|
||||
.service(process_payout),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DownloadBody {
|
||||
pub url: String,
|
||||
@@ -9,6 +9,15 @@ use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("midas")
|
||||
.service(init_checkout)
|
||||
.service(init_customer_portal)
|
||||
.service(handle_stripe_webhook),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CheckoutData {
|
||||
pub price_id: String,
|
||||
38
src/routes/v2/mod.rs
Normal file
38
src/routes/v2/mod.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
mod admin;
|
||||
mod auth;
|
||||
mod midas;
|
||||
mod moderation;
|
||||
mod notifications;
|
||||
pub(crate) mod project_creation;
|
||||
mod projects;
|
||||
mod reports;
|
||||
mod statistics;
|
||||
mod tags;
|
||||
mod teams;
|
||||
mod users;
|
||||
mod version_creation;
|
||||
mod version_file;
|
||||
mod versions;
|
||||
|
||||
pub use super::ApiError;
|
||||
|
||||
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
|
||||
cfg.service(
|
||||
actix_web::web::scope("v2")
|
||||
.configure(admin::config)
|
||||
.configure(auth::config)
|
||||
.configure(midas::config)
|
||||
.configure(moderation::config)
|
||||
.configure(notifications::config)
|
||||
.configure(project_creation::config)
|
||||
.configure(projects::config)
|
||||
.configure(reports::config)
|
||||
.configure(statistics::config)
|
||||
.configure(tags::config)
|
||||
.configure(teams::config)
|
||||
.configure(users::config)
|
||||
.configure(version_creation::config)
|
||||
.configure(version_file::config)
|
||||
.configure(versions::config),
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,15 @@ use actix_web::{delete, get, web, HttpRequest, HttpResponse};
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("moderation")
|
||||
.service(get_projects)
|
||||
.service(ban_user)
|
||||
.service(unban_user),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ResultCount {
|
||||
#[serde(default = "default_count")]
|
||||
@@ -7,6 +7,17 @@ use actix_web::{delete, get, web, HttpRequest, HttpResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(notifications_get);
|
||||
cfg.service(notifications_delete);
|
||||
|
||||
cfg.service(
|
||||
web::scope("notification")
|
||||
.service(notification_get)
|
||||
.service(notification_delete),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct NotificationIds {
|
||||
pub ids: String,
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::version_creation::InitialVersionData;
|
||||
use crate::database::models;
|
||||
use crate::file_hosting::{FileHost, FileHostingError};
|
||||
use crate::models::error::ApiError;
|
||||
@@ -6,7 +7,6 @@ use crate::models::projects::{
|
||||
VersionStatus,
|
||||
};
|
||||
use crate::models::users::UserId;
|
||||
use crate::routes::version_creation::InitialVersionData;
|
||||
use crate::search::indexing::IndexingError;
|
||||
use crate::util::auth::{get_user_from_headers, AuthenticationError};
|
||||
use crate::util::routes::read_from_field;
|
||||
@@ -25,6 +25,10 @@ use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
|
||||
cfg.service(project_create);
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CreateError {
|
||||
#[error("Environment Error")]
|
||||
@@ -24,6 +24,30 @@ use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(project_search);
|
||||
cfg.service(projects_get);
|
||||
cfg.service(projects_edit);
|
||||
cfg.service(random_projects_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("project")
|
||||
.service(project_get)
|
||||
.service(project_get_check)
|
||||
.service(project_delete)
|
||||
.service(project_edit)
|
||||
.service(project_icon_edit)
|
||||
.service(delete_project_icon)
|
||||
.service(add_gallery_item)
|
||||
.service(edit_gallery_item)
|
||||
.service(delete_gallery_item)
|
||||
.service(project_follow)
|
||||
.service(project_unfollow)
|
||||
.service(project_schedule)
|
||||
.service(web::scope("{project_id}").service(dependency_list)),
|
||||
);
|
||||
}
|
||||
|
||||
#[get("search")]
|
||||
pub async fn project_search(
|
||||
web::Query(info): web::Query<SearchRequest>,
|
||||
@@ -12,6 +12,12 @@ use futures::StreamExt;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(reports);
|
||||
cfg.service(report_create);
|
||||
cfg.service(delete_report);
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateReport {
|
||||
pub report_type: String,
|
||||
@@ -3,6 +3,10 @@ use actix_web::{get, web, HttpResponse};
|
||||
use serde_json::json;
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(get_stats);
|
||||
}
|
||||
|
||||
#[get("statistics")]
|
||||
pub async fn get_stats(
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -12,6 +12,22 @@ use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(teams_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("team")
|
||||
.service(team_members_get)
|
||||
.service(edit_team_member)
|
||||
.service(transfer_ownership)
|
||||
.service(add_team_member)
|
||||
.service(join_team)
|
||||
.service(remove_team_member),
|
||||
);
|
||||
|
||||
cfg.service(web::scope("project").service(team_members_get_project));
|
||||
}
|
||||
|
||||
#[get("{id}/members")]
|
||||
pub async fn team_members_get_project(
|
||||
req: HttpRequest,
|
||||
@@ -22,6 +22,24 @@ use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(user_auth_get);
|
||||
cfg.service(users_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("user")
|
||||
.service(user_get)
|
||||
.service(projects_list)
|
||||
.service(user_delete)
|
||||
.service(user_edit)
|
||||
.service(user_icon_edit)
|
||||
.service(user_notifications)
|
||||
.service(user_follows)
|
||||
.service(user_payouts)
|
||||
.service(user_payouts_request),
|
||||
);
|
||||
}
|
||||
|
||||
#[get("user")]
|
||||
pub async fn user_auth_get(
|
||||
req: HttpRequest,
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::project_creation::{CreateError, UploadedFile};
|
||||
use crate::database::models;
|
||||
use crate::database::models::notification_item::NotificationBuilder;
|
||||
use crate::database::models::version_item::{
|
||||
@@ -10,7 +11,6 @@ use crate::models::projects::{
|
||||
Version, VersionFile, VersionId, VersionStatus, VersionType,
|
||||
};
|
||||
use crate::models::teams::Permissions;
|
||||
use crate::routes::project_creation::{CreateError, UploadedFile};
|
||||
use crate::util::auth::get_user_from_headers;
|
||||
use crate::util::routes::read_from_field;
|
||||
use crate::util::validate::validation_errors_to_string;
|
||||
@@ -26,6 +26,12 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(version_create);
|
||||
|
||||
cfg.service(web::scope("version").service(upload_file_to_version));
|
||||
}
|
||||
|
||||
fn default_requested_status() -> VersionStatus {
|
||||
VersionStatus::Listed
|
||||
}
|
||||
@@ -13,6 +13,23 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("version_file")
|
||||
.service(delete_file)
|
||||
.service(get_version_from_hash)
|
||||
.service(download_version)
|
||||
.service(get_update_from_hash),
|
||||
);
|
||||
|
||||
cfg.service(
|
||||
web::scope("version_files")
|
||||
.service(get_versions_from_hashes)
|
||||
.service(download_files)
|
||||
.service(update_files),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct HashQuery {
|
||||
#[serde(default = "default_algorithm")]
|
||||
@@ -16,6 +16,24 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(versions_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("version")
|
||||
.service(version_get)
|
||||
.service(version_delete)
|
||||
.service(version_edit)
|
||||
.service(version_schedule),
|
||||
);
|
||||
|
||||
cfg.service(
|
||||
web::scope("project/{project_id}")
|
||||
.service(version_list)
|
||||
.service(version_project_get),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct VersionListFilters {
|
||||
pub game_versions: Option<String>,
|
||||
13
src/routes/v3/mod.rs
Normal file
13
src/routes/v3/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
pub use super::ApiError;
|
||||
use actix_web::{web, HttpResponse};
|
||||
use serde_json::json;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(web::scope("v3").route("", web::get().to(hello_world)));
|
||||
}
|
||||
|
||||
pub async fn hello_world() -> Result<HttpResponse, ApiError> {
|
||||
Ok(HttpResponse::Ok().json(json!({
|
||||
"hello": "world",
|
||||
})))
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::routes::project_creation::CreateError;
|
||||
use crate::routes::v2::project_creation::CreateError;
|
||||
use crate::routes::ApiError;
|
||||
use actix_multipart::Field;
|
||||
use actix_web::web::Payload;
|
||||
|
||||
Reference in New Issue
Block a user