Initial commit
This commit is contained in:
commit
bd9b07052b
81 changed files with 5516 additions and 0 deletions
53
http/src/requests/authors.rs
Normal file
53
http/src/requests/authors.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
use eva::data;
|
||||
|
||||
use viendesu_core::{
|
||||
errors,
|
||||
requests::authors as reqs,
|
||||
types::{Patch, author, file, user},
|
||||
};
|
||||
|
||||
use crate::requests::status_code;
|
||||
|
||||
#[serde_with::apply(Patch => #[serde(default)])]
|
||||
#[data]
|
||||
pub struct Update {
|
||||
pub title: Patch<author::Title>,
|
||||
pub description: Patch<Option<author::Description>>,
|
||||
pub pfp: Patch<Option<file::Id>>,
|
||||
pub slug: Patch<author::Slug>,
|
||||
pub verified: Patch<bool>,
|
||||
}
|
||||
|
||||
impl_req!(Update => [reqs::update::Ok; reqs::update::Err]);
|
||||
|
||||
status_code::direct!(reqs::update::Ok => OK);
|
||||
status_code::map!(reqs::update::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Create {
|
||||
pub title: author::Title,
|
||||
pub slug: author::Slug,
|
||||
pub description: Option<author::Description>,
|
||||
pub owner: Option<user::Id>,
|
||||
}
|
||||
|
||||
impl_req!(Create => [reqs::create::Ok; reqs::create::Err]);
|
||||
|
||||
status_code::direct!(reqs::create::Ok => OK);
|
||||
status_code::map!(reqs::create::Err => [NotFound, AlreadyExists, NoSuchUser]);
|
||||
|
||||
#[data]
|
||||
pub struct Get {}
|
||||
|
||||
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);
|
||||
|
||||
status_code::direct!(reqs::get::Ok => OK);
|
||||
status_code::map!(reqs::get::Err => [NotFound]);
|
||||
|
||||
const _: () = {
|
||||
use errors::authors::*;
|
||||
use status_code::direct;
|
||||
|
||||
direct!(NotFound => NOT_FOUND);
|
||||
direct!(AlreadyExists => BAD_REQUEST);
|
||||
};
|
||||
56
http/src/requests/boards.rs
Normal file
56
http/src/requests/boards.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use eva::data;
|
||||
|
||||
use crate::requests::status_code;
|
||||
|
||||
use viendesu_core::{
|
||||
errors,
|
||||
requests::boards as reqs,
|
||||
types::{Patch, board, message},
|
||||
};
|
||||
|
||||
#[data]
|
||||
pub struct Get {}
|
||||
|
||||
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);
|
||||
|
||||
status_code::direct!(reqs::get::Ok => OK);
|
||||
status_code::map!(reqs::get::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Edit {
|
||||
pub text: Patch<message::Text>,
|
||||
pub slug: Patch<Option<board::Slug>>,
|
||||
}
|
||||
|
||||
impl_req!(Edit => [reqs::edit::Ok; reqs::edit::Err]);
|
||||
|
||||
status_code::direct!(reqs::edit::Ok => OK);
|
||||
status_code::map!(reqs::edit::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Delete {}
|
||||
|
||||
impl_req!(Delete => [reqs::delete::Ok; reqs::delete::Err]);
|
||||
|
||||
status_code::direct!(reqs::delete::Ok => OK);
|
||||
status_code::map!(reqs::delete::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Create {
|
||||
pub slug: board::Slug,
|
||||
pub initial_message: message::Text,
|
||||
pub by: Option<message::ById>,
|
||||
}
|
||||
|
||||
impl_req!(Create => [reqs::create::Ok; reqs::create::Err]);
|
||||
|
||||
status_code::direct!(reqs::create::Ok => OK);
|
||||
status_code::map!(reqs::create::Err => [AlreadyExists]);
|
||||
|
||||
const _: () = {
|
||||
use errors::boards::*;
|
||||
use status_code::direct;
|
||||
|
||||
direct!(AlreadyExists => BAD_REQUEST);
|
||||
direct!(NotFound => NOT_FOUND);
|
||||
};
|
||||
81
http/src/requests/games.rs
Normal file
81
http/src/requests/games.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use eva::data;
|
||||
|
||||
use crate::requests::status_code;
|
||||
|
||||
use viendesu_core::{
|
||||
errors,
|
||||
requests::games as reqs,
|
||||
types::{Patch, author, file, game},
|
||||
};
|
||||
|
||||
#[data]
|
||||
#[serde_with::apply(Patch => #[serde(default)])]
|
||||
pub struct Update {
|
||||
pub title: Patch<game::Title>,
|
||||
pub description: Patch<Option<game::Description>>,
|
||||
pub slug: Patch<game::Slug>,
|
||||
pub thumbnail: Patch<Option<file::Id>>,
|
||||
pub genres: Patch<game::Genres>,
|
||||
pub badges: Patch<game::Badges>,
|
||||
pub tags: Patch<game::Tags>,
|
||||
pub screenshots: Patch<game::Screenshots>,
|
||||
pub published: Patch<bool>,
|
||||
}
|
||||
|
||||
impl_req!(Update => [reqs::update::Ok; reqs::update::Err]);
|
||||
|
||||
status_code::direct!(reqs::update::Ok => OK);
|
||||
status_code::map!(reqs::update::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Search {
|
||||
pub query: Option<game::SearchQuery>,
|
||||
pub author: Option<author::Selector>,
|
||||
#[serde(default)]
|
||||
pub include: reqs::search::Condition,
|
||||
#[serde(default)]
|
||||
pub exclude: reqs::search::Condition,
|
||||
#[serde(default)]
|
||||
pub order: reqs::search::Order,
|
||||
#[serde(default)]
|
||||
pub sort_by: reqs::search::SortBy,
|
||||
pub limit: Option<reqs::search::Limit>,
|
||||
}
|
||||
|
||||
impl_req!(Search => [reqs::search::Ok; reqs::search::Err]);
|
||||
|
||||
status_code::direct!(reqs::search::Ok => OK);
|
||||
status_code::map!(reqs::search::Err => [NoSuchAuthor]);
|
||||
|
||||
#[data]
|
||||
pub struct Get {}
|
||||
|
||||
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);
|
||||
|
||||
status_code::direct!(reqs::get::Ok => OK);
|
||||
status_code::map!(reqs::get::Err => [NotFound, NoSuchAuthor]);
|
||||
|
||||
#[data]
|
||||
pub struct Create {
|
||||
pub title: game::Title,
|
||||
pub description: Option<game::Description>,
|
||||
pub thumbnail: Option<file::Id>,
|
||||
pub author: author::Id,
|
||||
pub slug: Option<game::Slug>,
|
||||
pub vndb: Option<game::VndbId>,
|
||||
pub release_date: Option<game::ReleaseDate>,
|
||||
}
|
||||
|
||||
impl_req!(Create => [reqs::create::Ok; reqs::create::Err]);
|
||||
|
||||
status_code::direct!(reqs::create::Ok => CREATED);
|
||||
status_code::map!(reqs::create::Err => [AlreadyTaken, NoSuchAuthor]);
|
||||
|
||||
const _: () = {
|
||||
use errors::games::*;
|
||||
use status_code::direct;
|
||||
|
||||
direct!(NotFound => NOT_FOUND);
|
||||
direct!(NotAnOwner => FORBIDDEN);
|
||||
direct!(AlreadyTaken => BAD_REQUEST);
|
||||
};
|
||||
53
http/src/requests/messages.rs
Normal file
53
http/src/requests/messages.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
use eva::data;
|
||||
|
||||
use crate::requests::status_code;
|
||||
|
||||
use viendesu_core::{
|
||||
errors,
|
||||
requests::messages as reqs,
|
||||
types::{message, thread},
|
||||
};
|
||||
|
||||
#[data]
|
||||
pub struct Edit {
|
||||
pub text: message::Text,
|
||||
}
|
||||
|
||||
impl_req!(Edit => [reqs::edit::Ok; reqs::edit::Err]);
|
||||
|
||||
status_code::direct!(reqs::edit::Ok => OK);
|
||||
status_code::map!(reqs::edit::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Delete {}
|
||||
|
||||
impl_req!(Delete => [reqs::delete::Ok; reqs::delete::Err]);
|
||||
|
||||
status_code::direct!(reqs::delete::Ok => OK);
|
||||
status_code::map!(reqs::delete::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Post {
|
||||
pub thread: thread::Selector,
|
||||
pub text: message::Text,
|
||||
}
|
||||
|
||||
impl_req!(Post => [reqs::post::Ok; reqs::post::Err]);
|
||||
|
||||
status_code::direct!(reqs::post::Ok => OK);
|
||||
status_code::map!(reqs::post::Err => [NoSuchThread]);
|
||||
|
||||
#[data]
|
||||
pub struct Get {}
|
||||
|
||||
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);
|
||||
|
||||
status_code::direct!(reqs::get::Ok => OK);
|
||||
status_code::map!(reqs::get::Err => [NotFound]);
|
||||
|
||||
const _: () = {
|
||||
use errors::messages::*;
|
||||
use status_code::direct;
|
||||
|
||||
direct!(NotFound => NOT_FOUND);
|
||||
};
|
||||
32
http/src/requests/mod.rs
Normal file
32
http/src/requests/mod.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
pub mod status_code;
|
||||
|
||||
pub trait Request: Send + Sync + 'static + for<'de> serde::Deserialize<'de> {
|
||||
type Response: IsResponse;
|
||||
type Error: IsResponse;
|
||||
}
|
||||
|
||||
eva::trait_set! {
|
||||
pub trait IsResponse = status_code::HasStatusCode + serde::Serialize + Send + Sync + 'static;
|
||||
}
|
||||
|
||||
macro_rules! impl_req {
|
||||
($Input:ty => [$Ok:ty; $Err:ty]) => {
|
||||
const _: () = {
|
||||
use $crate::requests::Request;
|
||||
|
||||
impl Request for $Input {
|
||||
type Response = $Ok;
|
||||
type Error = $Err;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
pub mod users;
|
||||
|
||||
pub mod authors;
|
||||
pub mod games;
|
||||
|
||||
pub mod boards;
|
||||
pub mod messages;
|
||||
pub mod threads;
|
||||
81
http/src/requests/status_code.rs
Normal file
81
http/src/requests/status_code.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use http::status::StatusCode;
|
||||
|
||||
use viendesu_core::errors;
|
||||
|
||||
pub trait HasStatusCode {
|
||||
fn status_code(&self) -> StatusCode;
|
||||
}
|
||||
|
||||
impl<O: HasStatusCode, E: HasStatusCode> HasStatusCode for Result<O, E> {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
Ok(o) => o.status_code(),
|
||||
Err(e) => e.status_code(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: HasStatusCode> HasStatusCode for errors::Generic<S> {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
Self::Aux(aux) => aux.status_code(),
|
||||
Self::Spec(spec) => spec.status_code(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasStatusCode for errors::Aux {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
use StatusCode as C;
|
||||
use errors::Aux::*;
|
||||
|
||||
match self {
|
||||
Unauthenticated => C::UNAUTHORIZED,
|
||||
InvalidRole(e) => e.status_code(),
|
||||
InvalidSession(e) => e.status_code(),
|
||||
Captcha(..) | Deserialization(..) => C::BAD_REQUEST,
|
||||
Db(..) | InternalError(..) | ObjectStore(..) | Mail(..) => C::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! map {
|
||||
($Ty:ty => [$($Item:ident),* $(,)?]) => {
|
||||
const _: () = {
|
||||
use $crate::requests::status_code::HasStatusCode;
|
||||
use ::http::status::StatusCode;
|
||||
|
||||
impl HasStatusCode for $Ty {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {$(
|
||||
Self::$Item(ref e) => e.status_code(),
|
||||
)*}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use map;
|
||||
|
||||
macro_rules! direct {
|
||||
($($ty:ty => $code:ident),* $(,)?) => {$(
|
||||
const _: () = {
|
||||
use $crate::requests::status_code::HasStatusCode;
|
||||
use ::http::status::StatusCode;
|
||||
|
||||
impl HasStatusCode for $ty {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::$code
|
||||
}
|
||||
}
|
||||
};
|
||||
)*};
|
||||
}
|
||||
|
||||
pub(crate) use direct;
|
||||
|
||||
direct! {
|
||||
errors::auth::InvalidRole => FORBIDDEN,
|
||||
errors::auth::InvalidSession => BAD_REQUEST,
|
||||
}
|
||||
66
http/src/requests/threads.rs
Normal file
66
http/src/requests/threads.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
use eva::data;
|
||||
|
||||
use crate::requests::status_code;
|
||||
|
||||
use viendesu_core::{
|
||||
errors,
|
||||
requests::threads as reqs,
|
||||
types::{Patch, board, message, thread},
|
||||
};
|
||||
|
||||
#[data]
|
||||
pub struct Get {}
|
||||
|
||||
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);
|
||||
|
||||
status_code::direct!(reqs::get::Ok => OK);
|
||||
status_code::map!(reqs::get::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Delete {}
|
||||
|
||||
impl_req!(Delete => [reqs::delete::Ok; reqs::delete::Err]);
|
||||
|
||||
status_code::direct!(reqs::delete::Ok => OK);
|
||||
status_code::map!(reqs::delete::Err => [NotFound]);
|
||||
|
||||
#[data]
|
||||
pub struct Edit {
|
||||
pub text: Patch<message::Text>,
|
||||
}
|
||||
|
||||
impl_req!(Edit => [reqs::edit::Ok; reqs::edit::Err]);
|
||||
|
||||
status_code::direct!(reqs::edit::Ok => OK);
|
||||
status_code::map!(reqs::edit::Err => [NotFound, NotAnOwner]);
|
||||
|
||||
#[data]
|
||||
pub struct Search {
|
||||
#[serde(default)]
|
||||
pub limit: reqs::search::Limit,
|
||||
pub after: Option<thread::Id>,
|
||||
}
|
||||
|
||||
impl_req!(Search => [reqs::search::Ok; reqs::search::Err]);
|
||||
|
||||
status_code::direct!(reqs::search::Ok => OK);
|
||||
status_code::map!(reqs::search::Err => []);
|
||||
|
||||
#[data]
|
||||
pub struct Create {
|
||||
pub board: board::Selector,
|
||||
pub initial_message: message::Text,
|
||||
}
|
||||
|
||||
impl_req!(Create => [reqs::create::Ok; reqs::create::Err]);
|
||||
|
||||
status_code::direct!(reqs::create::Ok => CREATED);
|
||||
status_code::map!(reqs::create::Err => [NoSuchBoard]);
|
||||
|
||||
const _: () = {
|
||||
use errors::threads::*;
|
||||
use status_code::direct;
|
||||
|
||||
direct!(NotAnOwner => FORBIDDEN);
|
||||
direct!(NotFound => NOT_FOUND);
|
||||
};
|
||||
102
http/src/requests/users.rs
Normal file
102
http/src/requests/users.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use eva::data;
|
||||
|
||||
use viendesu_core::{
|
||||
errors,
|
||||
requests::users as reqs,
|
||||
types::{Patch, file, user as core},
|
||||
};
|
||||
|
||||
use super::status_code;
|
||||
|
||||
#[data]
|
||||
pub struct CheckAuth {}
|
||||
|
||||
impl_req!(CheckAuth => [reqs::check_auth::Ok; reqs::check_auth::Err]);
|
||||
status_code::direct!(reqs::check_auth::Ok => OK);
|
||||
status_code::map!(reqs::check_auth::Err => []);
|
||||
|
||||
#[data]
|
||||
#[non_exhaustive]
|
||||
#[derive(Default)]
|
||||
pub struct Get {}
|
||||
|
||||
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);
|
||||
status_code::map!(reqs::get::Err => [NotFound]);
|
||||
status_code::direct!(reqs::get::Ok => OK);
|
||||
|
||||
#[data]
|
||||
pub struct SignIn {
|
||||
pub nickname: core::Nickname,
|
||||
pub password: core::Password,
|
||||
}
|
||||
|
||||
impl_req!(SignIn => [reqs::sign_in::Ok; reqs::sign_in::Err]);
|
||||
status_code::map!(reqs::sign_in::Err => [NotFound, InvalidPassword, MustCompleteSignUp]);
|
||||
status_code::direct!(reqs::sign_in::Ok => OK);
|
||||
|
||||
#[data]
|
||||
#[non_exhaustive]
|
||||
#[derive(Default)]
|
||||
pub struct ConfirmSignUp {}
|
||||
|
||||
impl_req!(ConfirmSignUp => [reqs::confirm_sign_up::Ok; reqs::confirm_sign_up::Err]);
|
||||
status_code::direct!(reqs::confirm_sign_up::Ok => OK);
|
||||
status_code::map!(reqs::confirm_sign_up::Err => [NotFoundOrCompleted, InvalidSignUpToken]);
|
||||
|
||||
#[data]
|
||||
pub struct SignUp {
|
||||
pub nickname: core::Nickname,
|
||||
pub email: core::Email,
|
||||
pub password: core::Password,
|
||||
pub display_name: Option<core::DisplayName>,
|
||||
}
|
||||
|
||||
impl_req!(SignUp => [reqs::sign_up::Ok; reqs::sign_up::Err]);
|
||||
status_code::direct!(reqs::sign_up::Ok => CREATED);
|
||||
status_code::map!(reqs::sign_up::Err => [AlreadyTaken]);
|
||||
|
||||
#[serde_with::apply(
|
||||
Patch => #[serde(default)]
|
||||
)]
|
||||
#[data]
|
||||
#[non_exhaustive]
|
||||
#[derive(Default)]
|
||||
pub struct Update {
|
||||
pub nickname: Patch<core::Nickname>,
|
||||
pub display_name: Patch<Option<core::DisplayName>>,
|
||||
pub bio: Patch<Option<core::Bio>>,
|
||||
pub password: Patch<core::Password>,
|
||||
pub role: Patch<core::Role>,
|
||||
pub pfp: Patch<Option<file::Id>>,
|
||||
pub email: Patch<core::Email>,
|
||||
}
|
||||
|
||||
impl From<reqs::update::Update> for Update {
|
||||
fn from(u: reqs::update::Update) -> Self {
|
||||
Self {
|
||||
nickname: u.nickname,
|
||||
display_name: u.display_name,
|
||||
bio: u.bio,
|
||||
password: u.password,
|
||||
role: u.role,
|
||||
pfp: u.pfp,
|
||||
email: u.email,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_req!(Update => [reqs::update::Ok; reqs::update::Err]);
|
||||
status_code::direct!(reqs::update::Ok => OK);
|
||||
status_code::map!(reqs::update::Err => [NotFound]);
|
||||
|
||||
const _: () = {
|
||||
use errors::users::*;
|
||||
use status_code::direct;
|
||||
|
||||
direct!(NotFound => NOT_FOUND);
|
||||
direct!(InvalidPassword => FORBIDDEN);
|
||||
direct!(MustCompleteSignUp => FORBIDDEN);
|
||||
direct!(AlreadyTaken => BAD_REQUEST);
|
||||
direct!(NotFoundOrCompleted => BAD_REQUEST);
|
||||
direct!(InvalidSignUpToken => BAD_REQUEST);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue