Add utoipa info for v2 routes (#5775)
* wip: add v2 docs, routes to config, paths * fix up path prefixes * fix leading slashes * fix slash route * fix more slashes * wip: full utopification of v2 * convert last few v2 routes to utoipa
This commit is contained in:
@@ -15,12 +15,13 @@ mod versions;
|
||||
pub use super::ApiError;
|
||||
use crate::util::cors::default_cors;
|
||||
|
||||
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
|
||||
pub fn utoipa_config(
|
||||
cfg: &mut utoipa_actix_web::service_config::ServiceConfig,
|
||||
) {
|
||||
cfg.service(
|
||||
actix_web::web::scope("v2")
|
||||
utoipa_actix_web::scope("/v2")
|
||||
.wrap(default_cors())
|
||||
.configure(super::internal::admin::config)
|
||||
// Todo: separate these- they need to also follow v2-v3 conversion
|
||||
.configure(super::internal::session::config)
|
||||
.configure(super::internal::flows::config)
|
||||
.configure(super::internal::pats::config)
|
||||
|
||||
@@ -8,8 +8,8 @@ use crate::{database::redis::RedisPool, routes::v2_reroute};
|
||||
use actix_web::{HttpRequest, HttpResponse, get, web};
|
||||
use serde::Deserialize;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(web::scope("moderation").service(get_projects));
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(utoipa_actix_web::scope("/moderation").service(get_projects));
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -22,7 +22,31 @@ fn default_count() -> u16 {
|
||||
100
|
||||
}
|
||||
|
||||
#[get("projects")]
|
||||
/// Get projects in the moderation queue.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getModerationProjects",
|
||||
params(
|
||||
(
|
||||
"count" = Option<u16>,
|
||||
Query,
|
||||
description = "Maximum number of projects to return"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_READ"]))
|
||||
)]
|
||||
#[get("/projects")]
|
||||
pub async fn get_projects(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
|
||||
@@ -10,13 +10,12 @@ use crate::routes::v3;
|
||||
use actix_web::{HttpRequest, HttpResponse, delete, get, patch, web};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(notifications_get);
|
||||
cfg.service(notifications_delete);
|
||||
cfg.service(notifications_read);
|
||||
|
||||
cfg.service(
|
||||
web::scope("notification")
|
||||
utoipa_actix_web::scope("/notification")
|
||||
.service(notification_get)
|
||||
.service(notification_read)
|
||||
.service(notification_delete),
|
||||
@@ -28,7 +27,31 @@ pub struct NotificationIds {
|
||||
pub ids: String,
|
||||
}
|
||||
|
||||
#[get("notifications")]
|
||||
/// Get multiple notifications by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getNotifications",
|
||||
params(
|
||||
(
|
||||
"ids" = String,
|
||||
Query,
|
||||
description = "The JSON array of notification IDs"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_READ"]))
|
||||
)]
|
||||
#[get("/notifications")]
|
||||
pub async fn notifications_get(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<NotificationIds>,
|
||||
@@ -57,7 +80,25 @@ pub async fn notifications_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}")]
|
||||
/// Get a notification by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getNotification",
|
||||
params(("id" = NotificationId, Path, description = "The ID of the notification")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_READ"]))
|
||||
)]
|
||||
#[get("/{id}")]
|
||||
pub async fn notification_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(NotificationId,)>,
|
||||
@@ -83,7 +124,25 @@ pub async fn notification_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[patch("{id}")]
|
||||
/// Mark a notification as read.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "readNotification",
|
||||
params(("id" = NotificationId, Path, description = "The ID of the notification")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}")]
|
||||
pub async fn notification_read(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(NotificationId,)>,
|
||||
@@ -97,7 +156,25 @@ pub async fn notification_read(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}")]
|
||||
/// Delete a notification by ID.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteNotification",
|
||||
params(("id" = NotificationId, Path, description = "The ID of the notification")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}")]
|
||||
pub async fn notification_delete(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(NotificationId,)>,
|
||||
@@ -117,7 +194,31 @@ pub async fn notification_delete(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[patch("notifications")]
|
||||
/// Mark multiple notifications as read.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "readNotifications",
|
||||
params(
|
||||
(
|
||||
"ids" = String,
|
||||
Query,
|
||||
description = "The JSON array of notification IDs"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_WRITE"]))
|
||||
)]
|
||||
#[patch("/notifications")]
|
||||
pub async fn notifications_read(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<NotificationIds>,
|
||||
@@ -137,7 +238,31 @@ pub async fn notifications_read(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("notifications")]
|
||||
/// Delete multiple notifications by ID.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteNotifications",
|
||||
params(
|
||||
(
|
||||
"ids" = String,
|
||||
Query,
|
||||
description = "The JSON array of notification IDs"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_WRITE"]))
|
||||
)]
|
||||
#[delete("/notifications")]
|
||||
pub async fn notifications_delete(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<NotificationIds>,
|
||||
|
||||
@@ -25,7 +25,7 @@ use validator::Validate;
|
||||
|
||||
use super::version_creation::InitialVersionData;
|
||||
|
||||
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(project_create);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,24 @@ struct ProjectCreateData {
|
||||
pub organization_id: Option<models::ids::OrganizationId>,
|
||||
}
|
||||
|
||||
/// Create a new project with initial versions.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "createProject",
|
||||
request_body(
|
||||
content(("multipart/form-data")),
|
||||
description = "Multipart payload containing `data` and uploaded files"
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_CREATE"]))
|
||||
)]
|
||||
#[post("/project")]
|
||||
pub async fn project_create(
|
||||
req: HttpRequest,
|
||||
|
||||
@@ -21,14 +21,13 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(project_search);
|
||||
cfg.service(projects_get);
|
||||
cfg.service(projects_edit);
|
||||
cfg.service(random_projects_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("project")
|
||||
utoipa_actix_web::scope("/project")
|
||||
.service(project_get)
|
||||
.service(project_get_check)
|
||||
.service(project_delete)
|
||||
@@ -42,7 +41,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
.service(project_unfollow)
|
||||
.service(super::teams::team_members_get_project)
|
||||
.service(
|
||||
web::scope("{project_id}")
|
||||
utoipa_actix_web::scope("/{project_id}")
|
||||
.service(super::versions::version_list)
|
||||
.service(super::versions::version_project_get)
|
||||
.service(dependency_list),
|
||||
@@ -50,7 +49,43 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
#[get("search")]
|
||||
/// Search projects.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "searchProjects",
|
||||
params(
|
||||
(
|
||||
"query" = Option<String>,
|
||||
Query,
|
||||
description = "The query to search for"
|
||||
),
|
||||
(
|
||||
"facets" = Option<String>,
|
||||
Query,
|
||||
description = "Search facets JSON"
|
||||
),
|
||||
(
|
||||
"index" = Option<String>,
|
||||
Query,
|
||||
description = "Search index to use"
|
||||
),
|
||||
(
|
||||
"offset" = Option<String>,
|
||||
Query,
|
||||
description = "Search result offset"
|
||||
),
|
||||
(
|
||||
"limit" = Option<String>,
|
||||
Query,
|
||||
description = "Maximum number of search results"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[get("/search")]
|
||||
pub async fn project_search(
|
||||
web::Query(info): web::Query<SearchRequest>,
|
||||
search_backend: web::Data<dyn SearchBackend>,
|
||||
@@ -141,13 +176,29 @@ fn parse_facet(facet: &str) -> Option<(String, String, String)> {
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Validate)]
|
||||
#[derive(Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct RandomProjects {
|
||||
#[validate(range(min = 1, max = 100))]
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[get("projects_random")]
|
||||
/// Get random projects.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "randomProjects",
|
||||
params(
|
||||
(
|
||||
"count" = u32,
|
||||
Query,
|
||||
description = "Number of projects to return"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[get("/projects_random")]
|
||||
pub async fn random_projects_get(
|
||||
web::Query(count): web::Query<RandomProjects>,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -174,7 +225,20 @@ pub async fn random_projects_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("projects")]
|
||||
/// Get multiple projects by ID or slug.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getProjects",
|
||||
params(
|
||||
(
|
||||
"ids" = String,
|
||||
Query,
|
||||
description = "The JSON array of project IDs or slugs"
|
||||
)
|
||||
),
|
||||
responses((status = 200, description = "Expected response to a valid request"))
|
||||
)]
|
||||
#[get("/projects")]
|
||||
pub async fn projects_get(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<ProjectIds>,
|
||||
@@ -205,7 +269,20 @@ pub async fn projects_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}")]
|
||||
/// Get a project by ID or slug.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getProject",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{id}")]
|
||||
pub async fn project_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -241,7 +318,20 @@ pub async fn project_get(
|
||||
}
|
||||
|
||||
//checks the validity of a project id or slug
|
||||
#[get("{id}/check")]
|
||||
/// Check that a project ID or slug exists.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "checkProjectValidity",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{id}/check")]
|
||||
pub async fn project_get_check(
|
||||
info: web::Path<(String,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -253,13 +343,26 @@ pub async fn project_get_check(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, utoipa::ToSchema)]
|
||||
struct DependencyInfo {
|
||||
pub projects: Vec<LegacyProject>,
|
||||
pub versions: Vec<LegacyVersion>,
|
||||
}
|
||||
|
||||
#[get("dependencies")]
|
||||
/// Get dependency projects and versions for a project.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getDependencies",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/dependencies")]
|
||||
pub async fn dependency_list(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -305,7 +408,7 @@ pub async fn dependency_list(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
#[derive(Serialize, Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct EditProject {
|
||||
#[validate(
|
||||
length(min = 3, max = 64),
|
||||
@@ -404,7 +507,26 @@ pub struct EditProject {
|
||||
pub monetization_status: Option<MonetizationStatus>,
|
||||
}
|
||||
|
||||
#[patch("{id}")]
|
||||
/// Modify a project.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "modifyProject",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
request_body = EditProject,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}")]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn project_edit(
|
||||
req: HttpRequest,
|
||||
@@ -579,7 +701,7 @@ pub async fn project_edit(
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Validate)]
|
||||
#[derive(Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct BulkEditProject {
|
||||
#[validate(length(max = 3))]
|
||||
pub categories: Option<Vec<String>>,
|
||||
@@ -642,7 +764,29 @@ pub struct BulkEditProject {
|
||||
pub discord_url: Option<Option<String>>,
|
||||
}
|
||||
|
||||
#[patch("projects")]
|
||||
/// Bulk-edit multiple projects.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "patchProjects",
|
||||
params(
|
||||
(
|
||||
"ids" = String,
|
||||
Query,
|
||||
description = "The JSON array of project IDs or slugs"
|
||||
)
|
||||
),
|
||||
request_body = BulkEditProject,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[patch("/projects")]
|
||||
pub async fn projects_edit(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<ProjectIds>,
|
||||
@@ -739,12 +883,40 @@ pub async fn projects_edit(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct Extension {
|
||||
pub ext: String,
|
||||
}
|
||||
|
||||
#[patch("{id}/icon")]
|
||||
/// Change a project's icon.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "changeProjectIcon",
|
||||
params(
|
||||
("id" = String, Path, description = "The ID or slug of the project"),
|
||||
(
|
||||
"ext" = String,
|
||||
Query,
|
||||
description = "Image extension (png, jpg, jpeg, bmp, gif, webp, svg, svgz, rgb)"
|
||||
)
|
||||
),
|
||||
request_body(
|
||||
content(
|
||||
("image/png"),
|
||||
("image/jpeg"),
|
||||
("image/bmp"),
|
||||
("image/gif"),
|
||||
("image/webp"),
|
||||
("image/svg+xml")
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}/icon")]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn project_icon_edit(
|
||||
web::Query(ext): web::Query<Extension>,
|
||||
@@ -771,7 +943,22 @@ pub async fn project_icon_edit(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}/icon")]
|
||||
/// Delete a project's icon.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteProjectIcon",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}/icon")]
|
||||
pub async fn delete_project_icon(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -793,7 +980,7 @@ pub async fn delete_project_icon(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
#[derive(Serialize, Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct GalleryCreateQuery {
|
||||
pub featured: bool,
|
||||
#[validate(length(min = 1, max = 255))]
|
||||
@@ -803,7 +990,63 @@ pub struct GalleryCreateQuery {
|
||||
pub ordering: Option<i64>,
|
||||
}
|
||||
|
||||
#[post("{id}/gallery")]
|
||||
/// Add a gallery image to a project.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "addGalleryImage",
|
||||
params(
|
||||
("id" = String, Path, description = "The ID or slug of the project"),
|
||||
(
|
||||
"ext" = String,
|
||||
Query,
|
||||
description = "Image extension (png, jpg, jpeg, bmp, gif, webp, svg, svgz, rgb)"
|
||||
),
|
||||
(
|
||||
"featured" = bool,
|
||||
Query,
|
||||
description = "Whether this image is featured"
|
||||
),
|
||||
(
|
||||
"title" = Option<String>,
|
||||
Query,
|
||||
description = "Image title"
|
||||
),
|
||||
(
|
||||
"description" = Option<String>,
|
||||
Query,
|
||||
description = "Image description"
|
||||
),
|
||||
(
|
||||
"ordering" = Option<i64>,
|
||||
Query,
|
||||
description = "Image ordering"
|
||||
)
|
||||
),
|
||||
request_body(
|
||||
content(
|
||||
("image/png"),
|
||||
("image/jpeg"),
|
||||
("image/bmp"),
|
||||
("image/gif"),
|
||||
("image/webp"),
|
||||
("image/svg+xml")
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[post("/{id}/gallery")]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn add_gallery_item(
|
||||
web::Query(ext): web::Query<Extension>,
|
||||
@@ -837,7 +1080,7 @@ pub async fn add_gallery_item(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
#[derive(Serialize, Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct GalleryEditQuery {
|
||||
/// The url of the gallery item to edit
|
||||
pub url: String,
|
||||
@@ -859,7 +1102,48 @@ pub struct GalleryEditQuery {
|
||||
pub ordering: Option<i64>,
|
||||
}
|
||||
|
||||
#[patch("{id}/gallery")]
|
||||
/// Modify a gallery image.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "modifyGalleryImage",
|
||||
params(
|
||||
("id" = String, Path, description = "The ID or slug of the project"),
|
||||
("url" = String, Query, description = "URL of the image to edit"),
|
||||
(
|
||||
"featured" = Option<bool>,
|
||||
Query,
|
||||
description = "Whether this image is featured"
|
||||
),
|
||||
(
|
||||
"title" = Option<Option<String>>,
|
||||
Query,
|
||||
description = "Image title"
|
||||
),
|
||||
(
|
||||
"description" = Option<Option<String>>,
|
||||
Query,
|
||||
description = "Image description"
|
||||
),
|
||||
(
|
||||
"ordering" = Option<i64>,
|
||||
Query,
|
||||
description = "Image ordering"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}/gallery")]
|
||||
pub async fn edit_gallery_item(
|
||||
req: HttpRequest,
|
||||
web::Query(item): web::Query<GalleryEditQuery>,
|
||||
@@ -885,12 +1169,30 @@ pub async fn edit_gallery_item(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct GalleryDeleteQuery {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[delete("{id}/gallery")]
|
||||
/// Delete a gallery image.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteGalleryImage",
|
||||
params(
|
||||
("id" = String, Path, description = "The ID or slug of the project"),
|
||||
("url" = String, Query, description = "URL of the image to delete")
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}/gallery")]
|
||||
pub async fn delete_gallery_item(
|
||||
req: HttpRequest,
|
||||
web::Query(item): web::Query<GalleryDeleteQuery>,
|
||||
@@ -912,7 +1214,22 @@ pub async fn delete_gallery_item(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}")]
|
||||
/// Delete a project by ID or slug.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteProject",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_DELETE"]))
|
||||
)]
|
||||
#[delete("/{id}")]
|
||||
pub async fn project_delete(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -935,7 +1252,22 @@ pub async fn project_delete(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[post("{id}/follow")]
|
||||
/// Follow a project.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "followProject",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_WRITE"]))
|
||||
)]
|
||||
#[post("/{id}/follow")]
|
||||
pub async fn project_follow(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -949,7 +1281,22 @@ pub async fn project_follow(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}/follow")]
|
||||
/// Unfollow a project.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "unfollowProject",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}/follow")]
|
||||
pub async fn project_unfollow(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use actix_web::{HttpRequest, HttpResponse, delete, get, patch, post, web};
|
||||
use serde::Deserialize;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(reports_get);
|
||||
cfg.service(reports);
|
||||
cfg.service(report_create);
|
||||
@@ -17,7 +17,21 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(report_get);
|
||||
}
|
||||
|
||||
#[post("report")]
|
||||
/// Create a report for a project, version, or user.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "submitReport",
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["REPORT_CREATE"]))
|
||||
)]
|
||||
#[post("/report")]
|
||||
pub async fn report_create(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -40,7 +54,7 @@ pub async fn report_create(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct ReportsRequestOptions {
|
||||
#[serde(default = "default_count")]
|
||||
count: u16,
|
||||
@@ -55,7 +69,31 @@ fn default_all() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[get("report")]
|
||||
/// Get open reports for the current user.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getOpenReports",
|
||||
params(
|
||||
(
|
||||
"count" = Option<u16>,
|
||||
Query,
|
||||
description = "Maximum number of reports to return"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["REPORT_READ"]))
|
||||
)]
|
||||
#[get("/report")]
|
||||
pub async fn reports(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -88,12 +126,36 @@ pub async fn reports(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct ReportIds {
|
||||
pub ids: String,
|
||||
}
|
||||
|
||||
#[get("reports")]
|
||||
/// Get multiple reports by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getReports",
|
||||
params(
|
||||
(
|
||||
"ids" = String,
|
||||
Query,
|
||||
description = "The JSON array of report IDs"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["REPORT_READ"]))
|
||||
)]
|
||||
#[get("/reports")]
|
||||
pub async fn reports_get(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<ReportIds>,
|
||||
@@ -122,7 +184,25 @@ pub async fn reports_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("report/{id}")]
|
||||
/// Get a report by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getReport",
|
||||
params(("id" = crate::models::ids::ReportId, Path, description = "The ID of the report")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["REPORT_READ"]))
|
||||
)]
|
||||
#[get("/report/{id}")]
|
||||
pub async fn report_get(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -145,14 +225,34 @@ pub async fn report_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Validate)]
|
||||
#[derive(Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct EditReport {
|
||||
#[validate(length(max = 65536))]
|
||||
pub body: Option<String>,
|
||||
pub closed: Option<bool>,
|
||||
}
|
||||
|
||||
#[patch("report/{id}")]
|
||||
/// Modify a report.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "modifyReport",
|
||||
params(("id" = crate::models::ids::ReportId, Path, description = "The ID of the report")),
|
||||
request_body = EditReport,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["REPORT_WRITE"]))
|
||||
)]
|
||||
#[patch("/report/{id}")]
|
||||
pub async fn report_edit(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -178,7 +278,25 @@ pub async fn report_edit(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("report/{id}")]
|
||||
/// Delete a report by ID.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteReport",
|
||||
params(("id" = crate::models::ids::ReportId, Path, description = "The ID of the report")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["REPORT_DELETE"]))
|
||||
)]
|
||||
#[delete("/report/{id}")]
|
||||
pub async fn report_delete(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
|
||||
@@ -5,11 +5,11 @@ use crate::routes::{
|
||||
};
|
||||
use actix_web::{HttpResponse, get, web};
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(get_stats);
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(serde::Serialize, utoipa::ToSchema)]
|
||||
pub struct V2Stats {
|
||||
pub projects: Option<i64>,
|
||||
pub versions: Option<i64>,
|
||||
@@ -17,7 +17,19 @@ pub struct V2Stats {
|
||||
pub files: Option<i64>,
|
||||
}
|
||||
|
||||
#[get("statistics")]
|
||||
/// Get aggregate instance statistics.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "statistics",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = V2Stats
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/statistics")]
|
||||
pub async fn get_stats(
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
|
||||
@@ -12,9 +12,9 @@ use actix_web::{HttpResponse, get, web};
|
||||
use chrono::{DateTime, Utc};
|
||||
use itertools::Itertools;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("tag")
|
||||
utoipa_actix_web::scope("/tag")
|
||||
.service(category_list)
|
||||
.service(loader_list)
|
||||
.service(game_version_list)
|
||||
@@ -27,7 +27,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
|
||||
pub struct CategoryData {
|
||||
pub icon: String,
|
||||
pub name: String,
|
||||
@@ -35,7 +35,19 @@ pub struct CategoryData {
|
||||
pub header: String,
|
||||
}
|
||||
|
||||
#[get("category")]
|
||||
/// Get the list of project categories.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "categoryList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<CategoryData>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/category")]
|
||||
pub async fn category_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -62,14 +74,26 @@ pub async fn category_list(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
|
||||
pub struct LoaderData {
|
||||
pub icon: String,
|
||||
pub name: String,
|
||||
pub supported_project_types: Vec<String>,
|
||||
}
|
||||
|
||||
#[get("loader")]
|
||||
/// Get the list of loaders.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "loaderList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<LoaderData>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/loader")]
|
||||
pub async fn loader_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -116,7 +140,7 @@ pub async fn loader_list(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
|
||||
pub struct GameVersionQueryData {
|
||||
pub version: String,
|
||||
pub version_type: String,
|
||||
@@ -124,14 +148,38 @@ pub struct GameVersionQueryData {
|
||||
pub major: bool,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[derive(serde::Deserialize, utoipa::ToSchema)]
|
||||
pub struct GameVersionQuery {
|
||||
#[serde(rename = "type")]
|
||||
type_: Option<String>,
|
||||
major: Option<bool>,
|
||||
}
|
||||
|
||||
#[get("game_version")]
|
||||
/// Get the list of game versions.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "versionList",
|
||||
params(
|
||||
(
|
||||
"type" = Option<String>,
|
||||
Query,
|
||||
description = "Optional game version type filter"
|
||||
),
|
||||
(
|
||||
"major" = Option<bool>,
|
||||
Query,
|
||||
description = "Whether to return only major versions"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<GameVersionQueryData>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/game_version")]
|
||||
pub async fn game_version_list(
|
||||
pool: web::Data<PgPool>,
|
||||
query: web::Query<GameVersionQuery>,
|
||||
@@ -185,13 +233,25 @@ pub async fn game_version_list(
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(serde::Serialize, utoipa::ToSchema)]
|
||||
pub struct License {
|
||||
pub short: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[get("license")]
|
||||
/// Get SPDX license identifiers and names.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "licenseList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<License>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/license")]
|
||||
pub async fn license_list() -> HttpResponse {
|
||||
let response = v3::tags::license_list().await;
|
||||
|
||||
@@ -212,13 +272,27 @@ pub async fn license_list() -> HttpResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(serde::Serialize, utoipa::ToSchema)]
|
||||
pub struct LicenseText {
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
#[get("license/{id}")]
|
||||
/// Get full license text by SPDX ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "licenseText",
|
||||
params(("id" = String, Path, description = "The license ID to get the text for")),
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = LicenseText
|
||||
),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[get("/license/{id}")]
|
||||
pub async fn license_text(
|
||||
params: web::Path<(String,)>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
@@ -240,7 +314,9 @@ pub async fn license_text(
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)]
|
||||
#[derive(
|
||||
serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug, utoipa::ToSchema,
|
||||
)]
|
||||
pub struct DonationPlatformQueryData {
|
||||
// The difference between name and short is removed in v3.
|
||||
// Now, the 'id' becomes the name, and the 'name' is removed (the frontend uses the id as the name)
|
||||
@@ -249,7 +325,19 @@ pub struct DonationPlatformQueryData {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[get("donation_platform")]
|
||||
/// Get available donation platforms.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "donationPlatformList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<DonationPlatformQueryData>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/donation_platform")]
|
||||
pub async fn donation_platform_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -295,7 +383,19 @@ pub async fn donation_platform_list(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[get("report_type")]
|
||||
/// Get valid report types.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "reportTypeList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<String>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/report_type")]
|
||||
pub async fn report_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -306,7 +406,19 @@ pub async fn report_type_list(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[get("project_type")]
|
||||
/// Get valid project types.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "projectTypeList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<String>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/project_type")]
|
||||
pub async fn project_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -317,7 +429,19 @@ pub async fn project_type_list(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[get("side_type")]
|
||||
/// Get valid side-type values.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "sideTypeList",
|
||||
responses(
|
||||
(
|
||||
status = 200,
|
||||
description = "Expected response to a valid request",
|
||||
body = Vec<String>
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/side_type")]
|
||||
pub async fn side_type_list() -> Result<HttpResponse, ApiError> {
|
||||
// Original side types are no longer reflected in the database.
|
||||
// Therefore, we hardcode and return all the fields that are supported by our v2 conversion logic.
|
||||
|
||||
@@ -12,11 +12,10 @@ use ariadne::ids::UserId;
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(teams_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("team")
|
||||
utoipa_actix_web::scope("/team")
|
||||
.service(team_members_get)
|
||||
.service(edit_team_member)
|
||||
.service(transfer_ownership)
|
||||
@@ -31,7 +30,20 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
// also the members of the organization's team if the project is associated with an organization
|
||||
// (Unlike team_members_get_project, which only returns the members of the project's team)
|
||||
// They can be differentiated by the "organization_permissions" field being null or not
|
||||
#[get("{id}/members")]
|
||||
/// Get a project's team members.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getProjectTeamMembers",
|
||||
params(("id" = String, Path, description = "The ID or slug of the project")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{id}/members")]
|
||||
pub async fn team_members_get_project(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -62,7 +74,15 @@ pub async fn team_members_get_project(
|
||||
}
|
||||
|
||||
// Returns all members of a team, but not necessarily those of a project-team's organization (unlike team_members_get_project)
|
||||
#[get("{id}/members")]
|
||||
/// Get a team's members.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getTeamMembers",
|
||||
params(("id" = TeamId, Path, description = "The ID of the team")),
|
||||
responses((status = 200, description = "Expected response to a valid request")),
|
||||
security(("bearer_auth" = ["PROJECT_READ"]))
|
||||
)]
|
||||
#[get("/{id}/members")]
|
||||
pub async fn team_members_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId,)>,
|
||||
@@ -87,12 +107,19 @@ pub async fn team_members_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct TeamIds {
|
||||
pub ids: String,
|
||||
}
|
||||
|
||||
#[get("teams")]
|
||||
/// Get the members of multiple teams.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getTeams",
|
||||
params(("ids" = String, Query, description = "The JSON array of team IDs")),
|
||||
responses((status = 200, description = "Expected response to a valid request"))
|
||||
)]
|
||||
#[get("/teams")]
|
||||
pub async fn teams_get(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<TeamIds>,
|
||||
@@ -127,7 +154,25 @@ pub async fn teams_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[post("{id}/join")]
|
||||
/// Join a team with a pending invite.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "joinTeam",
|
||||
params(("id" = TeamId, Path, description = "The ID of the team")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[post("/{id}/join")]
|
||||
pub async fn join_team(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId,)>,
|
||||
@@ -149,7 +194,7 @@ fn default_ordering() -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Clone, utoipa::ToSchema)]
|
||||
pub struct NewTeamMember {
|
||||
pub user_id: UserId,
|
||||
#[serde(default = "default_role")]
|
||||
@@ -165,7 +210,26 @@ pub struct NewTeamMember {
|
||||
pub ordering: i64,
|
||||
}
|
||||
|
||||
#[post("{id}/members")]
|
||||
/// Add a member to a team.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "addTeamMember",
|
||||
params(("id" = TeamId, Path, description = "The ID of the team")),
|
||||
request_body = NewTeamMember,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[post("/{id}/members")]
|
||||
pub async fn add_team_member(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId,)>,
|
||||
@@ -194,7 +258,7 @@ pub async fn add_team_member(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Clone, utoipa::ToSchema)]
|
||||
pub struct EditTeamMember {
|
||||
pub permissions: Option<ProjectPermissions>,
|
||||
pub organization_permissions: Option<OrganizationPermissions>,
|
||||
@@ -203,7 +267,33 @@ pub struct EditTeamMember {
|
||||
pub ordering: Option<i64>,
|
||||
}
|
||||
|
||||
#[patch("{id}/members/{user_id}")]
|
||||
/// Modify a team member.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "modifyTeamMember",
|
||||
params(
|
||||
("id" = TeamId, Path, description = "The ID of the team"),
|
||||
(
|
||||
"user_id" = UserId,
|
||||
Path,
|
||||
description = "The ID of the user to modify"
|
||||
)
|
||||
),
|
||||
request_body = EditTeamMember,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}/members/{user_id}")]
|
||||
pub async fn edit_team_member(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId, UserId)>,
|
||||
@@ -231,12 +321,31 @@ pub async fn edit_team_member(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct TransferOwnership {
|
||||
pub user_id: UserId,
|
||||
}
|
||||
|
||||
#[patch("{id}/owner")]
|
||||
/// Transfer team ownership.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "transferTeamOwnership",
|
||||
params(("id" = TeamId, Path, description = "The ID of the team")),
|
||||
request_body = TransferOwnership,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}/owner")]
|
||||
pub async fn transfer_ownership(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId,)>,
|
||||
@@ -260,7 +369,32 @@ pub async fn transfer_ownership(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}/members/{user_id}")]
|
||||
/// Remove a member from a team.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteTeamMember",
|
||||
params(
|
||||
("id" = TeamId, Path, description = "The ID of the team"),
|
||||
(
|
||||
"user_id" = UserId,
|
||||
Path,
|
||||
description = "The ID of the user to remove"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["PROJECT_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}/members/{user_id}")]
|
||||
pub async fn remove_team_member(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(TeamId, UserId)>,
|
||||
|
||||
@@ -11,17 +11,31 @@ use crate::routes::{ApiError, v2_reroute, v3};
|
||||
use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
|
||||
use serde::Deserialize;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("thread")
|
||||
utoipa_actix_web::scope("/thread")
|
||||
.service(thread_get)
|
||||
.service(thread_send_message),
|
||||
);
|
||||
cfg.service(web::scope("message").service(message_delete));
|
||||
cfg.service(utoipa_actix_web::scope("/message").service(message_delete));
|
||||
cfg.service(threads_get);
|
||||
}
|
||||
|
||||
#[get("{id}")]
|
||||
/// Get a thread by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getThread",
|
||||
params(("id" = ThreadId, Path, description = "The ID of the thread")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["THREAD_READ"]))
|
||||
)]
|
||||
#[get("/{id}")]
|
||||
pub async fn thread_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(ThreadId,)>,
|
||||
@@ -34,12 +48,26 @@ pub async fn thread_get(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct ThreadIds {
|
||||
pub ids: String,
|
||||
}
|
||||
|
||||
#[get("threads")]
|
||||
/// Get multiple threads by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getThreads",
|
||||
params(("ids" = String, Query, description = "The JSON array of thread IDs")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["THREAD_READ"]))
|
||||
)]
|
||||
#[get("/threads")]
|
||||
pub async fn threads_get(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<ThreadIds>,
|
||||
@@ -70,12 +98,28 @@ pub async fn threads_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct NewThreadMessage {
|
||||
pub body: MessageBody,
|
||||
}
|
||||
|
||||
#[post("{id}")]
|
||||
/// Send a message to a thread.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "sendThreadMessage",
|
||||
params(("id" = ThreadId, Path, description = "The ID of the thread")),
|
||||
request_body = NewThreadMessage,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["THREAD_WRITE"]))
|
||||
)]
|
||||
#[post("/{id}")]
|
||||
pub async fn thread_send_message(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(ThreadId,)>,
|
||||
@@ -100,7 +144,25 @@ pub async fn thread_send_message(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}")]
|
||||
/// Delete a thread message by ID.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteThreadMessage",
|
||||
params(("id" = ThreadMessageId, Path, description = "The ID of the message")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["THREAD_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}")]
|
||||
pub async fn message_delete(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(ThreadMessageId,)>,
|
||||
|
||||
@@ -14,12 +14,11 @@ use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(user_auth_get);
|
||||
cfg.service(users_get);
|
||||
|
||||
cfg.service(
|
||||
web::scope("user")
|
||||
utoipa_actix_web::scope("/user")
|
||||
.service(user_get)
|
||||
.service(projects_list)
|
||||
.service(user_delete)
|
||||
@@ -31,7 +30,20 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
#[get("user")]
|
||||
/// Get the current user from the authorization header.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getUserFromAuth",
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_READ"]))
|
||||
)]
|
||||
#[get("/user")]
|
||||
pub async fn user_auth_get(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -52,12 +64,19 @@ pub async fn user_auth_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct UserIds {
|
||||
pub ids: String,
|
||||
}
|
||||
|
||||
#[get("users")]
|
||||
/// Get multiple users by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getUsers",
|
||||
params(("ids" = String, Query, description = "The JSON array of user IDs")),
|
||||
responses((status = 200, description = "Expected response to a valid request"))
|
||||
)]
|
||||
#[get("/users")]
|
||||
pub async fn users_get(
|
||||
web::Query(ids): web::Query<UserIds>,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -82,7 +101,20 @@ pub async fn users_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}")]
|
||||
/// Get a user by ID or username.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getUser",
|
||||
params(("id" = String, Path, description = "The ID or username of the user")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{id}")]
|
||||
pub async fn user_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -104,7 +136,20 @@ pub async fn user_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{user_id}/projects")]
|
||||
/// Get a user's projects.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getUserProjects",
|
||||
params(("user_id" = String, Path, description = "The ID or username of the user")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{user_id}/projects")]
|
||||
pub async fn projects_list(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -133,7 +178,7 @@ pub async fn projects_list(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
#[derive(Serialize, Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct EditUser {
|
||||
#[validate(length(min = 1, max = 39), regex(path = *crate::util::validate::RE_USERNAME))]
|
||||
pub username: Option<String>,
|
||||
@@ -156,7 +201,26 @@ pub struct EditUser {
|
||||
pub allow_friend_requests: Option<bool>,
|
||||
}
|
||||
|
||||
#[patch("{id}")]
|
||||
/// Modify a user.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "modifyUser",
|
||||
params(("id" = String, Path, description = "The ID or username of the user")),
|
||||
request_body = EditUser,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}")]
|
||||
pub async fn user_edit(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -186,12 +250,44 @@ pub async fn user_edit(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct Extension {
|
||||
pub ext: String,
|
||||
}
|
||||
|
||||
#[patch("{id}/icon")]
|
||||
/// Change a user's avatar.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "changeUserIcon",
|
||||
params(
|
||||
("id" = String, Path, description = "The ID or username of the user"),
|
||||
(
|
||||
"ext" = String,
|
||||
Query,
|
||||
description = "Image extension (png, jpg, jpeg, bmp, gif, webp, svg, svgz, rgb)"
|
||||
)
|
||||
),
|
||||
request_body(
|
||||
content(
|
||||
("image/png"),
|
||||
("image/jpeg"),
|
||||
("image/bmp"),
|
||||
("image/gif"),
|
||||
("image/webp"),
|
||||
("image/svg+xml")
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}/icon")]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn user_icon_edit(
|
||||
web::Query(ext): web::Query<Extension>,
|
||||
@@ -218,7 +314,22 @@ pub async fn user_icon_edit(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}/icon")]
|
||||
/// Remove a user's avatar.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteUserIcon",
|
||||
params(("id" = String, Path, description = "The ID or username of the user")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_WRITE"]))
|
||||
)]
|
||||
#[delete("/{id}/icon")]
|
||||
pub async fn user_icon_delete(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -240,7 +351,25 @@ pub async fn user_icon_delete(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[delete("{id}")]
|
||||
/// Delete a user by ID or username.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteUser",
|
||||
params(("id" = String, Path, description = "The ID or username of the user")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_DELETE"]))
|
||||
)]
|
||||
#[delete("/{id}")]
|
||||
pub async fn user_delete(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -255,7 +384,25 @@ pub async fn user_delete(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[get("{id}/follows")]
|
||||
/// Get projects followed by a user.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getFollowedProjects",
|
||||
params(("id" = String, Path, description = "The ID or username of the user")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["USER_READ"]))
|
||||
)]
|
||||
#[get("/{id}/follows")]
|
||||
pub async fn user_follows(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -284,7 +431,25 @@ pub async fn user_follows(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}/notifications")]
|
||||
/// Get notifications for a user.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getUserNotifications",
|
||||
params(("id" = String, Path, description = "The ID or username of the user")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["NOTIFICATION_READ"]))
|
||||
)]
|
||||
#[get("/{id}/notifications")]
|
||||
pub async fn user_notifications(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
|
||||
@@ -75,7 +75,25 @@ pub struct InitialVersionData {
|
||||
}
|
||||
|
||||
// under `/api/v1/version`
|
||||
#[post("version")]
|
||||
/// Create a version on an existing project.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "createVersion",
|
||||
request_body(
|
||||
content(("multipart/form-data")),
|
||||
description = "Multipart payload containing `data` and uploaded files"
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["VERSION_CREATE"]))
|
||||
)]
|
||||
#[post("/version")]
|
||||
pub async fn version_create(
|
||||
req: HttpRequest,
|
||||
payload: Multipart,
|
||||
@@ -280,7 +298,29 @@ async fn get_example_version_fields(
|
||||
}
|
||||
|
||||
// under /api/v1/version/{version_id}
|
||||
#[post("{version_id}/file")]
|
||||
/// Add files to an existing version.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "addFilesToVersion",
|
||||
params(("version_id" = VersionId, Path, description = "The ID of the version")),
|
||||
request_body(
|
||||
content(("multipart/form-data")),
|
||||
description = "Multipart payload containing files to upload"
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["VERSION_WRITE"]))
|
||||
)]
|
||||
#[post("/{version_id}/file")]
|
||||
pub async fn upload_file_to_version(
|
||||
req: HttpRequest,
|
||||
url_data: web::Path<(VersionId,)>,
|
||||
|
||||
@@ -11,9 +11,9 @@ use actix_web::{HttpRequest, HttpResponse, delete, get, post, web};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("version_file")
|
||||
utoipa_actix_web::scope("/version_file")
|
||||
.service(delete_file)
|
||||
.service(get_version_from_hash)
|
||||
.service(download_version)
|
||||
@@ -22,7 +22,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
|
||||
cfg.service(
|
||||
web::scope("version_files")
|
||||
utoipa_actix_web::scope("/version_files")
|
||||
.service(get_versions_from_hashes)
|
||||
.service(update_files)
|
||||
.service(update_files_many)
|
||||
@@ -31,7 +31,36 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
}
|
||||
|
||||
// under /api/v1/version_file/{hash}
|
||||
#[get("{version_id}")]
|
||||
/// Get version metadata by file hash.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "versionFromHash",
|
||||
params(
|
||||
(
|
||||
"version_id" = String,
|
||||
Path,
|
||||
description = "The hexadecimal file hash"
|
||||
),
|
||||
(
|
||||
"algorithm" = Option<String>,
|
||||
Query,
|
||||
description = "Hash algorithm to use (sha1 or sha512)"
|
||||
),
|
||||
(
|
||||
"version_id" = Option<crate::models::ids::VersionId>,
|
||||
Query,
|
||||
description = "Optional version ID when hash maps to multiple files"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{version_id}")]
|
||||
pub async fn get_version_from_hash(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -62,7 +91,36 @@ pub async fn get_version_from_hash(
|
||||
}
|
||||
|
||||
// under /api/v1/version_file/{hash}/download
|
||||
#[get("{version_id}/download")]
|
||||
/// Download a file by hash.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "downloadVersionFromHash",
|
||||
params(
|
||||
(
|
||||
"version_id" = String,
|
||||
Path,
|
||||
description = "The hexadecimal file hash"
|
||||
),
|
||||
(
|
||||
"algorithm" = Option<String>,
|
||||
Query,
|
||||
description = "Hash algorithm to use (sha1 or sha512)"
|
||||
),
|
||||
(
|
||||
"version_id" = Option<crate::models::ids::VersionId>,
|
||||
Query,
|
||||
description = "Optional version ID when hash maps to multiple files"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 302, description = "Temporary redirect to file URL"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{version_id}/download")]
|
||||
pub async fn download_version(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -85,7 +143,41 @@ pub async fn download_version(
|
||||
}
|
||||
|
||||
// under /api/v1/version_file/{hash}
|
||||
#[delete("{version_id}")]
|
||||
/// Delete a file by hash.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteFileFromHash",
|
||||
params(
|
||||
(
|
||||
"version_id" = String,
|
||||
Path,
|
||||
description = "The hexadecimal file hash"
|
||||
),
|
||||
(
|
||||
"algorithm" = Option<String>,
|
||||
Query,
|
||||
description = "Hash algorithm to use (sha1 or sha512)"
|
||||
),
|
||||
(
|
||||
"version_id" = Option<crate::models::ids::VersionId>,
|
||||
Query,
|
||||
description = "Optional version ID to delete from"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["VERSION_WRITE"]))
|
||||
)]
|
||||
#[delete("/{version_id}")]
|
||||
pub async fn delete_file(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -107,14 +199,45 @@ pub async fn delete_file(
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct UpdateData {
|
||||
pub loaders: Option<Vec<String>>,
|
||||
pub game_versions: Option<Vec<String>>,
|
||||
pub version_types: Option<Vec<VersionType>>,
|
||||
}
|
||||
|
||||
#[post("{version_id}/update")]
|
||||
/// Get the latest compatible version from a file hash.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "getLatestVersionFromHash",
|
||||
params(
|
||||
(
|
||||
"version_id" = String,
|
||||
Path,
|
||||
description = "The hexadecimal file hash"
|
||||
),
|
||||
(
|
||||
"algorithm" = Option<String>,
|
||||
Query,
|
||||
description = "Hash algorithm to use (sha1 or sha512)"
|
||||
),
|
||||
(
|
||||
"version_id" = Option<crate::models::ids::VersionId>,
|
||||
Query,
|
||||
description = "Optional version ID when hash maps to multiple files"
|
||||
)
|
||||
),
|
||||
request_body = UpdateData,
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[post("/{version_id}/update")]
|
||||
pub async fn get_update_from_hash(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -162,13 +285,23 @@ pub async fn get_update_from_hash(
|
||||
}
|
||||
|
||||
// Requests above with multiple versions below
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct FileHashes {
|
||||
pub algorithm: Option<String>,
|
||||
pub hashes: Vec<String>,
|
||||
}
|
||||
|
||||
// under /api/v2/version_files
|
||||
/// Get versions from file hashes.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "versionsFromHashes",
|
||||
request_body = FileHashes,
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[post("")]
|
||||
pub async fn get_versions_from_hashes(
|
||||
req: HttpRequest,
|
||||
@@ -210,7 +343,17 @@ pub async fn get_versions_from_hashes(
|
||||
}
|
||||
}
|
||||
|
||||
#[post("project")]
|
||||
/// Get projects from file hashes.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "projectsFromHashes",
|
||||
request_body = FileHashes,
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[post("/project")]
|
||||
pub async fn get_projects_from_hashes(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
@@ -268,7 +411,7 @@ pub async fn get_projects_from_hashes(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct ManyUpdateData {
|
||||
pub algorithm: Option<String>, // Defaults to calculation based on size of hash
|
||||
pub hashes: Vec<String>,
|
||||
@@ -277,7 +420,17 @@ pub struct ManyUpdateData {
|
||||
pub version_types: Option<Vec<VersionType>>,
|
||||
}
|
||||
|
||||
#[post("update")]
|
||||
/// Get latest compatible versions for multiple hashes.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "getLatestVersionsFromHashes",
|
||||
request_body = ManyUpdateData,
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[post("/update")]
|
||||
pub async fn update_files(
|
||||
pool: web::Data<ReadOnlyPgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -316,7 +469,17 @@ pub async fn update_files(
|
||||
Ok(HttpResponse::Ok().json(v3_versions))
|
||||
}
|
||||
|
||||
#[post("update_many")]
|
||||
/// Get all latest compatible versions for multiple hashes.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "getLatestVersionsFromHashesMany",
|
||||
request_body = ManyUpdateData,
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[post("/update_many")]
|
||||
pub async fn update_files_many(
|
||||
pool: web::Data<ReadOnlyPgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
@@ -358,7 +521,7 @@ pub async fn update_files_many(
|
||||
Ok(HttpResponse::Ok().json(v3_versions))
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct FileUpdateData {
|
||||
pub hash: String,
|
||||
pub loaders: Option<Vec<String>>,
|
||||
@@ -366,13 +529,23 @@ pub struct FileUpdateData {
|
||||
pub version_types: Option<Vec<VersionType>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct ManyFileUpdateData {
|
||||
pub algorithm: Option<String>, // Defaults to calculation based on size of hash
|
||||
pub hashes: Vec<FileUpdateData>,
|
||||
}
|
||||
|
||||
#[post("update_individual")]
|
||||
/// Get latest versions with per-hash filters.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "getLatestVersionsFromHashesIndividual",
|
||||
request_body = ManyFileUpdateData,
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(status = 400, description = "Request was invalid, see given error")
|
||||
)
|
||||
)]
|
||||
#[post("/update_individual")]
|
||||
pub async fn update_individual_files(
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
|
||||
@@ -16,12 +16,11 @@ use actix_web::{HttpRequest, HttpResponse, delete, get, patch, web};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
|
||||
cfg.service(versions_get);
|
||||
cfg.service(super::version_creation::version_create);
|
||||
|
||||
cfg.service(
|
||||
web::scope("version")
|
||||
utoipa_actix_web::scope("/version")
|
||||
.service(version_get)
|
||||
.service(version_delete)
|
||||
.service(version_edit)
|
||||
@@ -29,7 +28,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Clone, utoipa::ToSchema)]
|
||||
pub struct VersionListFilters {
|
||||
pub game_versions: Option<String>,
|
||||
pub loaders: Option<String>,
|
||||
@@ -45,7 +44,46 @@ fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[get("version")]
|
||||
/// List versions for a project.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getProjectVersions",
|
||||
params(
|
||||
(
|
||||
"project_id" = String,
|
||||
Path,
|
||||
description = "The ID or slug of the project"
|
||||
),
|
||||
(
|
||||
"loaders" = Option<String>,
|
||||
Query,
|
||||
description = "JSON array of loaders to filter by"
|
||||
),
|
||||
(
|
||||
"game_versions" = Option<String>,
|
||||
Query,
|
||||
description = "JSON array of game versions to filter by"
|
||||
),
|
||||
(
|
||||
"featured" = Option<bool>,
|
||||
Query,
|
||||
description = "Filter by featured status"
|
||||
),
|
||||
(
|
||||
"include_changelog" = Option<bool>,
|
||||
Query,
|
||||
description = "Whether to include changelog fields"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/version")]
|
||||
pub async fn version_list(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
@@ -129,7 +167,31 @@ pub async fn version_list(
|
||||
}
|
||||
|
||||
// Given a project ID/slug and a version slug
|
||||
#[get("version/{slug}")]
|
||||
/// Get a project version by ID or version number.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getVersionFromIdOrNumber",
|
||||
params(
|
||||
(
|
||||
"project_id" = String,
|
||||
Path,
|
||||
description = "The ID or slug of the project"
|
||||
),
|
||||
(
|
||||
"slug" = String,
|
||||
Path,
|
||||
description = "The version ID or version number"
|
||||
)
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/version/{slug}")]
|
||||
pub async fn version_project_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String, String)>,
|
||||
@@ -157,14 +219,21 @@ pub async fn version_project_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct VersionIds {
|
||||
pub ids: String,
|
||||
#[serde(default = "default_true")]
|
||||
pub include_changelog: bool,
|
||||
}
|
||||
|
||||
#[get("versions")]
|
||||
/// Get multiple versions by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getVersions",
|
||||
params(("ids" = String, Query, description = "The JSON array of version IDs")),
|
||||
responses((status = 200, description = "Expected response to a valid request"))
|
||||
)]
|
||||
#[get("/versions")]
|
||||
pub async fn versions_get(
|
||||
req: HttpRequest,
|
||||
web::Query(ids): web::Query<VersionIds>,
|
||||
@@ -199,7 +268,20 @@ pub async fn versions_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{version_id}")]
|
||||
/// Get a version by ID.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "getVersion",
|
||||
params(("version_id" = models::ids::VersionId, Path, description = "The ID of the version")),
|
||||
responses(
|
||||
(status = 200, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[get("/{version_id}")]
|
||||
pub async fn version_get(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(models::ids::VersionId,)>,
|
||||
@@ -223,7 +305,7 @@ pub async fn version_get(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
#[derive(Serialize, Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct EditVersion {
|
||||
#[validate(
|
||||
length(min = 1, max = 64),
|
||||
@@ -251,14 +333,33 @@ pub struct EditVersion {
|
||||
pub file_types: Option<Vec<EditVersionFileType>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct EditVersionFileType {
|
||||
pub algorithm: String,
|
||||
pub hash: String,
|
||||
pub file_type: Option<FileType>,
|
||||
}
|
||||
|
||||
#[patch("{id}")]
|
||||
/// Modify an existing version.
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
operation_id = "modifyVersion",
|
||||
params(("id" = VersionId, Path, description = "The ID of the version")),
|
||||
request_body = EditVersion,
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["VERSION_WRITE"]))
|
||||
)]
|
||||
#[patch("/{id}")]
|
||||
pub async fn version_edit(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(VersionId,)>,
|
||||
@@ -350,7 +451,25 @@ pub async fn version_edit(
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
#[delete("{version_id}")]
|
||||
/// Delete a version by ID.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
operation_id = "deleteVersion",
|
||||
params(("version_id" = VersionId, Path, description = "The ID of the version")),
|
||||
responses(
|
||||
(status = 204, description = "Expected response to a valid request"),
|
||||
(
|
||||
status = 401,
|
||||
description = "Incorrect token scopes or no authorization to access the requested item(s)"
|
||||
),
|
||||
(
|
||||
status = 404,
|
||||
description = "The requested item(s) were not found or no authorization to access the requested item(s)"
|
||||
)
|
||||
),
|
||||
security(("bearer_auth" = ["VERSION_DELETE"]))
|
||||
)]
|
||||
#[delete("/{version_id}")]
|
||||
pub async fn version_delete(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(VersionId,)>,
|
||||
|
||||
Reference in New Issue
Block a user