Sanity checked all of V2 route conversions (#803)
* follows * all v2 routes now either convert or have a comment * added common structs, clippy * merge fix --------- Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
parent
9f798559cf
commit
d59c522f7f
@ -1,5 +1,8 @@
|
||||
// Legacy models from V2, where its useful to keep the struct for rerouting/conversion
|
||||
pub mod notifications;
|
||||
pub mod projects;
|
||||
pub mod reports;
|
||||
pub mod search;
|
||||
pub mod teams;
|
||||
pub mod threads;
|
||||
pub mod user;
|
||||
|
||||
52
src/models/v2/reports.rs
Normal file
52
src/models/v2/reports.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::models::ids::{ReportId, ThreadId, UserId};
|
||||
use crate::models::reports::{ItemType, Report};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LegacyReport {
|
||||
pub id: ReportId,
|
||||
pub report_type: String,
|
||||
pub item_id: String,
|
||||
pub item_type: LegacyItemType,
|
||||
pub reporter: UserId,
|
||||
pub body: String,
|
||||
pub created: DateTime<Utc>,
|
||||
pub closed: bool,
|
||||
pub thread_id: ThreadId,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum LegacyItemType {
|
||||
Project,
|
||||
Version,
|
||||
User,
|
||||
Unknown,
|
||||
}
|
||||
impl From<ItemType> for LegacyItemType {
|
||||
fn from(x: ItemType) -> Self {
|
||||
match x {
|
||||
ItemType::Project => LegacyItemType::Project,
|
||||
ItemType::Version => LegacyItemType::Version,
|
||||
ItemType::User => LegacyItemType::User,
|
||||
ItemType::Unknown => LegacyItemType::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Report> for LegacyReport {
|
||||
fn from(x: Report) -> Self {
|
||||
LegacyReport {
|
||||
id: x.id,
|
||||
report_type: x.report_type,
|
||||
item_id: x.item_id,
|
||||
item_type: x.item_type.into(),
|
||||
reporter: x.reporter,
|
||||
body: x.body,
|
||||
created: x.created,
|
||||
closed: x.closed,
|
||||
thread_id: x.thread_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
120
src/models/v2/threads.rs
Normal file
120
src/models/v2/threads.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use crate::models::ids::{ImageId, ProjectId, ReportId, ThreadId, ThreadMessageId};
|
||||
use crate::models::projects::ProjectStatus;
|
||||
use crate::models::users::{User, UserId};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LegacyThread {
|
||||
pub id: ThreadId,
|
||||
#[serde(rename = "type")]
|
||||
pub type_: LegacyThreadType,
|
||||
pub project_id: Option<ProjectId>,
|
||||
pub report_id: Option<ReportId>,
|
||||
pub messages: Vec<LegacyThreadMessage>,
|
||||
pub members: Vec<User>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LegacyThreadMessage {
|
||||
pub id: ThreadMessageId,
|
||||
pub author_id: Option<UserId>,
|
||||
pub body: LegacyMessageBody,
|
||||
pub created: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum LegacyMessageBody {
|
||||
Text {
|
||||
body: String,
|
||||
#[serde(default)]
|
||||
private: bool,
|
||||
replying_to: Option<ThreadMessageId>,
|
||||
#[serde(default)]
|
||||
associated_images: Vec<ImageId>,
|
||||
},
|
||||
StatusChange {
|
||||
new_status: ProjectStatus,
|
||||
old_status: ProjectStatus,
|
||||
},
|
||||
ThreadClosure,
|
||||
ThreadReopen,
|
||||
Deleted,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Copy, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum LegacyThreadType {
|
||||
Report,
|
||||
Project,
|
||||
DirectMessage,
|
||||
}
|
||||
|
||||
impl From<crate::models::v3::threads::ThreadType> for LegacyThreadType {
|
||||
fn from(t: crate::models::v3::threads::ThreadType) -> Self {
|
||||
match t {
|
||||
crate::models::v3::threads::ThreadType::Report => LegacyThreadType::Report,
|
||||
crate::models::v3::threads::ThreadType::Project => LegacyThreadType::Project,
|
||||
crate::models::v3::threads::ThreadType::DirectMessage => {
|
||||
LegacyThreadType::DirectMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::models::v3::threads::MessageBody> for LegacyMessageBody {
|
||||
fn from(b: crate::models::v3::threads::MessageBody) -> Self {
|
||||
match b {
|
||||
crate::models::v3::threads::MessageBody::Text {
|
||||
body,
|
||||
private,
|
||||
replying_to,
|
||||
associated_images,
|
||||
} => LegacyMessageBody::Text {
|
||||
body,
|
||||
private,
|
||||
replying_to,
|
||||
associated_images,
|
||||
},
|
||||
crate::models::v3::threads::MessageBody::StatusChange {
|
||||
new_status,
|
||||
old_status,
|
||||
} => LegacyMessageBody::StatusChange {
|
||||
new_status,
|
||||
old_status,
|
||||
},
|
||||
crate::models::v3::threads::MessageBody::ThreadClosure => {
|
||||
LegacyMessageBody::ThreadClosure
|
||||
}
|
||||
crate::models::v3::threads::MessageBody::ThreadReopen => {
|
||||
LegacyMessageBody::ThreadReopen
|
||||
}
|
||||
crate::models::v3::threads::MessageBody::Deleted => LegacyMessageBody::Deleted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::models::v3::threads::ThreadMessage> for LegacyThreadMessage {
|
||||
fn from(m: crate::models::v3::threads::ThreadMessage) -> Self {
|
||||
LegacyThreadMessage {
|
||||
id: m.id,
|
||||
author_id: m.author_id,
|
||||
body: m.body.into(),
|
||||
created: m.created,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::models::v3::threads::Thread> for LegacyThread {
|
||||
fn from(t: crate::models::v3::threads::Thread) -> Self {
|
||||
LegacyThread {
|
||||
id: t.id,
|
||||
type_: t.type_.into(),
|
||||
project_id: t.project_id,
|
||||
report_id: t.report_id,
|
||||
messages: t.messages.into_iter().map(|m| m.into()).collect(),
|
||||
members: t.members,
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/models/v2/user.rs
Normal file
53
src/models/v2/user.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use crate::{
|
||||
auth::AuthProvider,
|
||||
models::{
|
||||
ids::UserId,
|
||||
users::{Badges, Role, UserPayoutData},
|
||||
},
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct LegacyUser {
|
||||
pub id: UserId,
|
||||
pub username: String,
|
||||
pub name: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
pub created: DateTime<Utc>,
|
||||
pub role: Role,
|
||||
pub badges: Badges,
|
||||
|
||||
pub auth_providers: Option<Vec<AuthProvider>>, // this was changed in v3, but not changes ones we want to keep out of v2
|
||||
pub email: Option<String>,
|
||||
pub email_verified: Option<bool>,
|
||||
pub has_password: Option<bool>,
|
||||
pub has_totp: Option<bool>,
|
||||
pub payout_data: Option<UserPayoutData>, // this was changed in v3, but not ones we want to keep out of v2
|
||||
|
||||
// DEPRECATED. Always returns None
|
||||
pub github_id: Option<u64>,
|
||||
}
|
||||
|
||||
impl From<crate::models::v3::users::User> for LegacyUser {
|
||||
fn from(data: crate::models::v3::users::User) -> Self {
|
||||
Self {
|
||||
id: data.id,
|
||||
username: data.username,
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
email_verified: data.email_verified,
|
||||
avatar_url: data.avatar_url,
|
||||
bio: data.bio,
|
||||
created: data.created,
|
||||
role: data.role,
|
||||
badges: data.badges,
|
||||
payout_data: data.payout_data,
|
||||
auth_providers: data.auth_providers,
|
||||
has_password: data.has_password,
|
||||
has_totp: data.has_totp,
|
||||
github_id: data.github_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
use super::ApiError;
|
||||
use crate::models::projects::Project;
|
||||
use crate::models::v2::projects::LegacyProject;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::v3;
|
||||
use crate::{database::redis::RedisPool, routes::v2_reroute};
|
||||
@ -28,13 +30,22 @@ pub async fn get_projects(
|
||||
count: web::Query<ResultCount>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::moderation::get_projects(
|
||||
let response = v3::moderation::get_projects(
|
||||
req,
|
||||
pool,
|
||||
redis,
|
||||
pool.clone(),
|
||||
redis.clone(),
|
||||
web::Query(v3::moderation::ResultCount { count: count.count }),
|
||||
session_queue,
|
||||
)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert to V2 projects
|
||||
match v2_reroute::extract_ok_json::<Vec<Project>>(response).await {
|
||||
Ok(project) => {
|
||||
let legacy_projects = LegacyProject::from_many(project, &**pool, &redis).await?;
|
||||
Ok(HttpResponse::Ok().json(legacy_projects))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +85,7 @@ pub async fn notification_read(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::notifications::notification_read(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -98,6 +99,7 @@ pub async fn notification_delete(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::notifications::notification_delete(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -111,6 +113,7 @@ pub async fn notifications_read(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::notifications::notifications_read(
|
||||
req,
|
||||
web::Query(v3::notifications::NotificationIds { ids: ids.ids }),
|
||||
@ -130,6 +133,7 @@ pub async fn notifications_delete(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::notifications::notifications_delete(
|
||||
req,
|
||||
web::Query(v3::notifications::NotificationIds { ids: ids.ids }),
|
||||
|
||||
@ -2,11 +2,10 @@ use crate::database::models::categories::LinkPlatform;
|
||||
use crate::database::models::{project_item, version_item};
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::file_hosting::FileHost;
|
||||
use crate::models;
|
||||
use crate::models::projects::{
|
||||
Link, MonetizationStatus, Project, ProjectStatus, SearchRequest, Version,
|
||||
};
|
||||
use crate::models::v2::projects::{DonationLink, LegacyProject, LegacySideType};
|
||||
use crate::models::v2::projects::{DonationLink, LegacyProject, LegacySideType, LegacyVersion};
|
||||
use crate::models::v2::search::LegacySearchResults;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::v3::projects::ProjectIds;
|
||||
@ -223,6 +222,7 @@ pub async fn project_get_check(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns an id only, do not need to convert
|
||||
v3::projects::project_get_check(info, pool, redis)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -230,8 +230,8 @@ pub async fn project_get_check(
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct DependencyInfo {
|
||||
pub projects: Vec<Project>,
|
||||
pub versions: Vec<models::projects::Version>,
|
||||
pub projects: Vec<LegacyProject>,
|
||||
pub versions: Vec<LegacyVersion>,
|
||||
}
|
||||
|
||||
#[get("dependencies")]
|
||||
@ -242,10 +242,30 @@ pub async fn dependency_list(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// TODO: requires V2 conversion and tests, probably
|
||||
v3::projects::dependency_list(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
// TODO: tests, probably
|
||||
let response =
|
||||
v3::projects::dependency_list(req, info, pool.clone(), redis.clone(), session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
match v2_reroute::extract_ok_json::<crate::routes::v3::projects::DependencyInfo>(response).await
|
||||
{
|
||||
Ok(dependency_info) => {
|
||||
let converted_projects =
|
||||
LegacyProject::from_many(dependency_info.projects, &**pool, &redis).await?;
|
||||
let converted_versions = dependency_info
|
||||
.versions
|
||||
.into_iter()
|
||||
.map(LegacyVersion::from)
|
||||
.collect();
|
||||
|
||||
Ok(HttpResponse::Ok().json(DependencyInfo {
|
||||
projects: converted_projects,
|
||||
versions: converted_versions,
|
||||
}))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
@ -636,6 +656,7 @@ pub async fn projects_edit(
|
||||
}
|
||||
}
|
||||
|
||||
// This returns NoContent or failure so we don't need to do anything with it
|
||||
v3::projects::projects_edit(
|
||||
req,
|
||||
web::Query(ids),
|
||||
@ -673,6 +694,7 @@ pub async fn project_icon_edit(
|
||||
payload: web::Payload,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::project_icon_edit(
|
||||
web::Query(v3::projects::Extension { ext: ext.ext }),
|
||||
req,
|
||||
@ -696,6 +718,7 @@ pub async fn delete_project_icon(
|
||||
file_host: web::Data<Arc<dyn FileHost + Send + Sync>>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::delete_project_icon(req, info, pool, redis, file_host, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -724,6 +747,7 @@ pub async fn add_gallery_item(
|
||||
payload: web::Payload,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::add_gallery_item(
|
||||
web::Query(v3::projects::Extension { ext: ext.ext }),
|
||||
req,
|
||||
@ -775,6 +799,7 @@ pub async fn edit_gallery_item(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::edit_gallery_item(
|
||||
req,
|
||||
web::Query(v3::projects::GalleryEditQuery {
|
||||
@ -808,6 +833,7 @@ pub async fn delete_gallery_item(
|
||||
file_host: web::Data<Arc<dyn FileHost + Send + Sync>>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::delete_gallery_item(
|
||||
req,
|
||||
web::Query(v3::projects::GalleryDeleteQuery { url: item.url }),
|
||||
@ -830,6 +856,7 @@ pub async fn project_delete(
|
||||
config: web::Data<SearchConfig>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::project_delete(req, info, pool, redis, config, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -843,6 +870,7 @@ pub async fn project_follow(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::project_follow(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -856,6 +884,7 @@ pub async fn project_unfollow(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::projects::project_unfollow(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::models::ids::ImageId;
|
||||
use crate::models::reports::ItemType;
|
||||
use crate::models::reports::{ItemType, Report};
|
||||
use crate::models::v2::reports::LegacyReport;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::{v2_reroute, v3, ApiError};
|
||||
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
|
||||
@ -37,9 +38,18 @@ pub async fn report_create(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::reports::report_create(req, pool, body, redis, session_queue)
|
||||
let response = v3::reports::report_create(req, pool, body, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Report>(response).await {
|
||||
Ok(report) => {
|
||||
let report = LegacyReport::from(report);
|
||||
Ok(HttpResponse::Ok().json(report))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -65,7 +75,7 @@ pub async fn reports(
|
||||
count: web::Query<ReportsRequestOptions>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::reports::reports(
|
||||
let response = v3::reports::reports(
|
||||
req,
|
||||
pool,
|
||||
redis,
|
||||
@ -76,7 +86,16 @@ pub async fn reports(
|
||||
session_queue,
|
||||
)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<Report>>(response).await {
|
||||
Ok(reports) => {
|
||||
let reports: Vec<_> = reports.into_iter().map(LegacyReport::from).collect();
|
||||
Ok(HttpResponse::Ok().json(reports))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -92,7 +111,7 @@ pub async fn reports_get(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::reports::reports_get(
|
||||
let response = v3::reports::reports_get(
|
||||
req,
|
||||
web::Query(v3::reports::ReportIds { ids: ids.ids }),
|
||||
pool,
|
||||
@ -100,7 +119,16 @@ pub async fn reports_get(
|
||||
session_queue,
|
||||
)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<Report>>(response).await {
|
||||
Ok(report_list) => {
|
||||
let report_list: Vec<_> = report_list.into_iter().map(LegacyReport::from).collect();
|
||||
Ok(HttpResponse::Ok().json(report_list))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("report/{id}")]
|
||||
@ -111,9 +139,18 @@ pub async fn report_get(
|
||||
info: web::Path<(crate::models::reports::ReportId,)>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::reports::report_get(req, pool, redis, info, session_queue)
|
||||
let response = v3::reports::report_get(req, pool, redis, info, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Report>(response).await {
|
||||
Ok(report) => {
|
||||
let report = LegacyReport::from(report);
|
||||
Ok(HttpResponse::Ok().json(report))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Validate)]
|
||||
@ -133,6 +170,7 @@ pub async fn report_edit(
|
||||
edit_report: web::Json<EditReport>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let edit_report = edit_report.into_inner();
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::reports::report_edit(
|
||||
req,
|
||||
pool,
|
||||
@ -156,6 +194,7 @@ pub async fn report_delete(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert
|
||||
v3::reports::report_delete(req, pool, info, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
use crate::routes::{v2_reroute, v3, ApiError};
|
||||
use crate::routes::{
|
||||
v2_reroute,
|
||||
v3::{self, statistics::V3Stats},
|
||||
ApiError,
|
||||
};
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -6,9 +10,30 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(get_stats);
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct V2Stats {
|
||||
pub projects: Option<i64>,
|
||||
pub versions: Option<i64>,
|
||||
pub authors: Option<i64>,
|
||||
pub files: Option<i64>,
|
||||
}
|
||||
|
||||
#[get("statistics")]
|
||||
pub async fn get_stats(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
v3::statistics::get_stats(pool)
|
||||
let response = v3::statistics::get_stats(pool)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
match v2_reroute::extract_ok_json::<V3Stats>(response).await {
|
||||
Ok(stats) => {
|
||||
let stats = V2Stats {
|
||||
projects: stats.projects,
|
||||
versions: stats.versions,
|
||||
authors: stats.authors,
|
||||
files: stats.files,
|
||||
};
|
||||
Ok(HttpResponse::Ok().json(stats))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,9 +5,7 @@ use crate::database::models::loader_fields::LoaderFieldEnumValue;
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::models::v2::projects::LegacySideType;
|
||||
use crate::routes::v2_reroute::capitalize_first;
|
||||
use crate::routes::v3::tags::{
|
||||
LinkPlatformQueryData, LoaderData as LoaderDataV3, LoaderFieldsEnumQuery,
|
||||
};
|
||||
use crate::routes::v3::tags::{LinkPlatformQueryData, LoaderFieldsEnumQuery};
|
||||
use crate::routes::{v2_reroute, v3};
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use chrono::{DateTime, Utc};
|
||||
@ -42,7 +40,24 @@ pub async fn category_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::tags::category_list(pool, redis).await
|
||||
let response = v3::tags::category_list(pool, redis).await?;
|
||||
|
||||
// Convert to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<v3::tags::CategoryData>>(response).await {
|
||||
Ok(categories) => {
|
||||
let categories = categories
|
||||
.into_iter()
|
||||
.map(|c| CategoryData {
|
||||
icon: c.icon,
|
||||
name: c.name,
|
||||
project_type: c.project_type,
|
||||
header: c.header,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Ok(HttpResponse::Ok().json(categories))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
@ -60,7 +75,7 @@ pub async fn loader_list(
|
||||
let response = v3::tags::loader_list(pool, redis).await?;
|
||||
|
||||
// Convert to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<LoaderDataV3>>(response).await {
|
||||
match v2_reroute::extract_ok_json::<Vec<v3::tags::LoaderData>>(response).await {
|
||||
Ok(loaders) => {
|
||||
let loaders = loaders
|
||||
.into_iter()
|
||||
@ -151,26 +166,52 @@ pub async fn game_version_list(
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct License {
|
||||
short: String,
|
||||
name: String,
|
||||
pub short: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[get("license")]
|
||||
pub async fn license_list() -> HttpResponse {
|
||||
v3::tags::license_list().await
|
||||
let response = v3::tags::license_list().await;
|
||||
|
||||
// Convert to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<v3::tags::License>>(response).await {
|
||||
Ok(licenses) => {
|
||||
let licenses = licenses
|
||||
.into_iter()
|
||||
.map(|l| License {
|
||||
short: l.short,
|
||||
name: l.name,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
HttpResponse::Ok().json(licenses)
|
||||
}
|
||||
Err(response) => response,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct LicenseText {
|
||||
title: String,
|
||||
body: String,
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
#[get("license/{id}")]
|
||||
pub async fn license_text(params: web::Path<(String,)>) -> Result<HttpResponse, ApiError> {
|
||||
v3::tags::license_text(params)
|
||||
let license = v3::tags::license_text(params)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert to V2 format
|
||||
Ok(
|
||||
match v2_reroute::extract_ok_json::<v3::tags::LicenseText>(license).await {
|
||||
Ok(license) => HttpResponse::Ok().json(LicenseText {
|
||||
title: license.title,
|
||||
body: license.body,
|
||||
}),
|
||||
Err(response) => response,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)]
|
||||
@ -229,6 +270,7 @@ pub async fn report_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// This returns a list of strings directly, so we don't need to convert to v2 format.
|
||||
v3::tags::report_type_list(pool, redis)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -239,6 +281,7 @@ pub async fn project_type_list(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// This returns a list of strings directly, so we don't need to convert to v2 format.
|
||||
v3::tags::project_type_list(pool, redis)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
|
||||
@ -124,6 +124,7 @@ pub async fn join_team(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::teams::join_team(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -162,6 +163,7 @@ pub async fn add_team_member(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::teams::add_team_member(
|
||||
req,
|
||||
info,
|
||||
@ -199,6 +201,7 @@ pub async fn edit_team_member(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::teams::edit_team_member(
|
||||
req,
|
||||
info,
|
||||
@ -231,6 +234,7 @@ pub async fn transfer_ownership(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::teams::transfer_ownership(
|
||||
req,
|
||||
info,
|
||||
@ -253,6 +257,7 @@ pub async fn remove_team_member(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::teams::remove_team_member(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
|
||||
@ -3,7 +3,8 @@ use std::sync::Arc;
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::file_hosting::FileHost;
|
||||
use crate::models::ids::ThreadMessageId;
|
||||
use crate::models::threads::{MessageBody, ThreadId};
|
||||
use crate::models::threads::{MessageBody, Thread, ThreadId};
|
||||
use crate::models::v2::threads::LegacyThread;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::{v2_reroute, v3, ApiError};
|
||||
use actix_web::{delete, get, post, web, HttpRequest, HttpResponse};
|
||||
@ -48,7 +49,7 @@ pub async fn threads_get(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::threads::threads_get(
|
||||
let response = v3::threads::threads_get(
|
||||
req,
|
||||
web::Query(v3::threads::ThreadIds { ids: ids.ids }),
|
||||
pool,
|
||||
@ -56,7 +57,19 @@ pub async fn threads_get(
|
||||
session_queue,
|
||||
)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<Thread>>(response).await {
|
||||
Ok(threads) => {
|
||||
let threads = threads
|
||||
.into_iter()
|
||||
.map(LegacyThread::from)
|
||||
.collect::<Vec<_>>();
|
||||
Ok(HttpResponse::Ok().json(threads))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -74,6 +87,7 @@ pub async fn thread_send_message(
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let new_message = new_message.into_inner();
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::threads::thread_send_message(
|
||||
req,
|
||||
info,
|
||||
@ -95,9 +109,21 @@ pub async fn moderation_inbox(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::threads::moderation_inbox(req, pool, redis, session_queue)
|
||||
let response = v3::threads::moderation_inbox(req, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<Thread>>(response).await {
|
||||
Ok(threads) => {
|
||||
let threads = threads
|
||||
.into_iter()
|
||||
.map(LegacyThread::from)
|
||||
.collect::<Vec<_>>();
|
||||
Ok(HttpResponse::Ok().json(threads))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[post("{id}/read")]
|
||||
@ -108,6 +134,7 @@ pub async fn thread_read(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::threads::thread_read(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -122,6 +149,7 @@ pub async fn message_delete(
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
file_host: web::Data<Arc<dyn FileHost + Send + Sync>>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::threads::message_delete(req, info, pool, redis, session_queue, file_host)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
|
||||
@ -2,9 +2,10 @@ use crate::database::redis::RedisPool;
|
||||
use crate::file_hosting::FileHost;
|
||||
use crate::models::notifications::Notification;
|
||||
use crate::models::projects::Project;
|
||||
use crate::models::users::{Badges, Role};
|
||||
use crate::models::users::{Badges, Role, User};
|
||||
use crate::models::v2::notifications::LegacyNotification;
|
||||
use crate::models::v2::projects::LegacyProject;
|
||||
use crate::models::v2::user::LegacyUser;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::{v2_reroute, v3, ApiError};
|
||||
use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse};
|
||||
@ -38,9 +39,18 @@ pub async fn user_auth_get(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::users::user_auth_get(req, pool, redis, session_queue)
|
||||
let response = v3::users::user_auth_get(req, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<User>(response).await {
|
||||
Ok(user) => {
|
||||
let user = LegacyUser::from(user);
|
||||
Ok(HttpResponse::Ok().json(user))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -54,9 +64,19 @@ pub async fn users_get(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::users::users_get(web::Query(v3::users::UserIds { ids: ids.ids }), pool, redis)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
let response =
|
||||
v3::users::users_get(web::Query(v3::users::UserIds { ids: ids.ids }), pool, redis)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<Vec<User>>(response).await {
|
||||
Ok(users) => {
|
||||
let legacy_users: Vec<LegacyUser> = users.into_iter().map(LegacyUser::from).collect();
|
||||
Ok(HttpResponse::Ok().json(legacy_users))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}")]
|
||||
@ -65,9 +85,18 @@ pub async fn user_get(
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::users::user_get(info, pool, redis)
|
||||
let response = v3::users::user_get(info, pool, redis)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert response to V2 format
|
||||
match v2_reroute::extract_ok_json::<User>(response).await {
|
||||
Ok(user) => {
|
||||
let user = LegacyUser::from(user);
|
||||
Ok(HttpResponse::Ok().json(user))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{user_id}/projects")]
|
||||
@ -128,6 +157,7 @@ pub async fn user_edit(
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let new_user = new_user.into_inner();
|
||||
// Returns NoContent, so we don't need to convert to V2
|
||||
v3::users::user_edit(
|
||||
req,
|
||||
info,
|
||||
@ -164,6 +194,7 @@ pub async fn user_icon_edit(
|
||||
payload: web::Payload,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert to V2
|
||||
v3::users::user_icon_edit(
|
||||
web::Query(v3::users::Extension { ext: ext.ext }),
|
||||
req,
|
||||
@ -186,6 +217,7 @@ pub async fn user_delete(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert to V2
|
||||
v3::users::user_delete(req, info, pool, redis, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -199,9 +231,18 @@ pub async fn user_follows(
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
v3::users::user_follows(req, info, pool, redis, session_queue)
|
||||
let response = v3::users::user_follows(req, info, pool.clone(), redis.clone(), session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
.or_else(v2_reroute::flatten_404_error)?;
|
||||
|
||||
// Convert to V2 projects
|
||||
match v2_reroute::extract_ok_json::<Vec<Project>>(response).await {
|
||||
Ok(project) => {
|
||||
let legacy_projects = LegacyProject::from_many(project, &**pool, &redis).await?;
|
||||
Ok(HttpResponse::Ok().json(legacy_projects))
|
||||
}
|
||||
Err(response) => Ok(response),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}/notifications")]
|
||||
|
||||
@ -268,6 +268,7 @@ pub async fn upload_file_to_version(
|
||||
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, CreateError> {
|
||||
// Returns NoContent, so no need to convert to V2
|
||||
let response = v3::version_creation::upload_file_to_version(
|
||||
req,
|
||||
url_data,
|
||||
|
||||
@ -63,6 +63,7 @@ pub async fn download_version(
|
||||
hash_query: web::Query<HashQuery>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns TemporaryRedirect, so no need to convert to V2
|
||||
v3::version_file::download_version(req, info, pool, redis, hash_query, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -78,6 +79,7 @@ pub async fn delete_file(
|
||||
hash_query: web::Query<HashQuery>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so no need to convert to V2
|
||||
v3::version_file::delete_file(req, info, pool, redis, hash_query, session_queue)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
|
||||
@ -270,6 +270,7 @@ pub async fn version_delete(
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
search_config: web::Data<SearchConfig>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
v3::versions::version_delete(req, info, pool, redis, session_queue, search_config)
|
||||
.await
|
||||
.or_else(v2_reroute::flatten_404_error)
|
||||
@ -290,6 +291,7 @@ pub async fn version_schedule(
|
||||
scheduling_data: web::Json<SchedulingData>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
// Returns NoContent, so we don't need to convert the response
|
||||
let scheduling_data = scheduling_data.into_inner();
|
||||
let scheduling_data = v3::versions::SchedulingData {
|
||||
time: scheduling_data.time,
|
||||
|
||||
@ -939,8 +939,8 @@ pub async fn project_get_check(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct DependencyInfo {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DependencyInfo {
|
||||
pub projects: Vec<Project>,
|
||||
pub versions: Vec<models::projects::Version>,
|
||||
}
|
||||
|
||||
@ -1,12 +1,19 @@
|
||||
use crate::routes::ApiError;
|
||||
use actix_web::{web, HttpResponse};
|
||||
use serde_json::json;
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.route("statistics", web::get().to(get_stats));
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct V3Stats {
|
||||
pub projects: Option<i64>,
|
||||
pub versions: Option<i64>,
|
||||
pub authors: Option<i64>,
|
||||
pub files: Option<i64>,
|
||||
}
|
||||
|
||||
pub async fn get_stats(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError> {
|
||||
let projects = sqlx::query!(
|
||||
"
|
||||
@ -74,12 +81,12 @@ pub async fn get_stats(pool: web::Data<PgPool>) -> Result<HttpResponse, ApiError
|
||||
.fetch_one(&**pool)
|
||||
.await?;
|
||||
|
||||
let json = json!({
|
||||
"projects": projects.count,
|
||||
"versions": versions.count,
|
||||
"authors": authors.count,
|
||||
"files": files.count,
|
||||
});
|
||||
let v3_stats = V3Stats {
|
||||
projects: projects.count,
|
||||
versions: versions.count,
|
||||
authors: authors.count,
|
||||
files: files.count,
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().json(json))
|
||||
Ok(HttpResponse::Ok().json(v3_stats))
|
||||
}
|
||||
|
||||
@ -166,10 +166,10 @@ pub async fn loader_fields_list(
|
||||
Ok(HttpResponse::Ok().json(results))
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct License {
|
||||
short: String,
|
||||
name: String,
|
||||
pub short: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub async fn license_list() -> HttpResponse {
|
||||
@ -186,10 +186,10 @@ pub async fn license_list() -> HttpResponse {
|
||||
HttpResponse::Ok().json(results)
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct LicenseText {
|
||||
title: String,
|
||||
body: String,
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
pub async fn license_text(params: web::Path<(String,)>) -> Result<HttpResponse, ApiError> {
|
||||
|
||||
@ -1,22 +1,30 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use labrinth::models::{
|
||||
notifications::NotificationId,
|
||||
organizations::OrganizationId,
|
||||
projects::{
|
||||
Dependency, GalleryItem, License, ModeratorMessage, MonetizationStatus, ProjectId,
|
||||
ProjectStatus, VersionFile, VersionId, VersionStatus, VersionType,
|
||||
use labrinth::{
|
||||
auth::AuthProvider,
|
||||
models::{
|
||||
images::ImageId,
|
||||
notifications::NotificationId,
|
||||
organizations::OrganizationId,
|
||||
projects::{
|
||||
Dependency, GalleryItem, License, ModeratorMessage, MonetizationStatus, ProjectId,
|
||||
ProjectStatus, VersionFile, VersionId, VersionStatus, VersionType,
|
||||
},
|
||||
reports::ReportId,
|
||||
teams::{ProjectPermissions, TeamId},
|
||||
threads::{ThreadId, ThreadMessageId},
|
||||
users::{Badges, Role, User, UserId, UserPayoutData},
|
||||
},
|
||||
teams::{ProjectPermissions, TeamId},
|
||||
threads::ThreadId,
|
||||
users::{User, UserId},
|
||||
};
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Deserialize;
|
||||
|
||||
// Fields shared by every version of the API.
|
||||
// No struct in here should have ANY field that
|
||||
// is not present in *every* version of the API.
|
||||
|
||||
// Exceptions are fields that *should* be changing across the API, and older versions
|
||||
// should be unsupported on API version increase- for example, payouts related financial fields.
|
||||
|
||||
// These are used for common tests- tests that can be used on both V2 AND v3 of the API and have the same results.
|
||||
|
||||
// Any test that requires version-specific fields should have its own test that is not done for each version,
|
||||
@ -120,7 +128,7 @@ pub struct CommonNotificationAction {
|
||||
pub action_route: (String, String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum CommonItemType {
|
||||
Project,
|
||||
@ -139,3 +147,88 @@ impl CommonItemType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CommonReport {
|
||||
pub id: ReportId,
|
||||
pub report_type: String,
|
||||
pub item_id: String,
|
||||
pub item_type: CommonItemType,
|
||||
pub reporter: UserId,
|
||||
pub body: String,
|
||||
pub created: DateTime<Utc>,
|
||||
pub closed: bool,
|
||||
pub thread_id: ThreadId,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub enum LegacyItemType {
|
||||
Project,
|
||||
Version,
|
||||
User,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CommonThread {
|
||||
pub id: ThreadId,
|
||||
#[serde(rename = "type")]
|
||||
pub type_: CommonThreadType,
|
||||
pub project_id: Option<ProjectId>,
|
||||
pub report_id: Option<ReportId>,
|
||||
pub messages: Vec<CommonThreadMessage>,
|
||||
pub members: Vec<User>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CommonThreadMessage {
|
||||
pub id: ThreadMessageId,
|
||||
pub author_id: Option<UserId>,
|
||||
pub body: CommonMessageBody,
|
||||
pub created: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub enum CommonMessageBody {
|
||||
Text {
|
||||
body: String,
|
||||
#[serde(default)]
|
||||
private: bool,
|
||||
replying_to: Option<ThreadMessageId>,
|
||||
#[serde(default)]
|
||||
associated_images: Vec<ImageId>,
|
||||
},
|
||||
StatusChange {
|
||||
new_status: ProjectStatus,
|
||||
old_status: ProjectStatus,
|
||||
},
|
||||
ThreadClosure,
|
||||
ThreadReopen,
|
||||
Deleted,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub enum CommonThreadType {
|
||||
Report,
|
||||
Project,
|
||||
DirectMessage,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CommonUser {
|
||||
pub id: UserId,
|
||||
pub username: String,
|
||||
pub name: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
pub created: DateTime<Utc>,
|
||||
pub role: Role,
|
||||
pub badges: Badges,
|
||||
pub auth_providers: Option<Vec<AuthProvider>>,
|
||||
pub email: Option<String>,
|
||||
pub email_verified: Option<bool>,
|
||||
pub has_password: Option<bool>,
|
||||
pub has_totp: Option<bool>,
|
||||
pub payout_data: Option<UserPayoutData>,
|
||||
pub github_id: Option<u64>,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user