From d3c25799cd29d7e70c1012dcf27d4cdb459921cb Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 6 Oct 2025 20:24:47 +0300 Subject: [PATCH] impl rest of http --- core/src/types/author.rs | 2 +- core/src/types/entity.rs | 11 ++- http/src/client/authors.rs | 33 ++++++- http/src/client/games.rs | 82 ++++++++++++++++- http/src/server/response/mod.rs | 2 +- http/src/server/routes.rs | 158 ++++++++++++++++++++++++++++++++ 6 files changed, 277 insertions(+), 11 deletions(-) diff --git a/core/src/types/author.rs b/core/src/types/author.rs index 2ab74c0..32efbc2 100644 --- a/core/src/types/author.rs +++ b/core/src/types/author.rs @@ -11,7 +11,7 @@ use crate::types::{entity, file, slug, user}; #[data(copy, ord)] #[serde(untagged)] pub enum Selector { - #[display("{_0}")] + #[display("{}", _0.to_str())] Id(#[from] Id), #[display("@{_0}")] #[serde(with = "SlugStr")] diff --git a/core/src/types/entity.rs b/core/src/types/entity.rs index 5716c05..a1531d9 100644 --- a/core/src/types/entity.rs +++ b/core/src/types/entity.rs @@ -500,7 +500,7 @@ macro_rules! _define_eid { } /// Generic entity identifier. -#[data(copy, ord, not(serde, schemars, Debug), display("{}:{}", self.metadata().kind(), self.to_str()))] +#[data(copy, ord, not(serde, schemars, Debug), display("{}", self.to_str()))] #[derive(Hash)] pub struct Id(NonZeroU128); @@ -524,7 +524,14 @@ impl Id { impl fmt::Debug for Id { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Id").field(&self.to_str().as_str()).finish() + write!( + f, + "{}:{}", + self.metadata() + .kind() + .as_static_str(Some(eva::generic::Case::Snake)), + self.to_str() + ) } } diff --git a/http/src/client/authors.rs b/http/src/client/authors.rs index d0a002c..e6894ba 100644 --- a/http/src/client/authors.rs +++ b/http/src/client/authors.rs @@ -14,10 +14,39 @@ impl AuthorsRef for Hidden<'_> { impl AuthorsMut for Hidden<'_> { fn create(&mut self) -> impl CallStep { - self.do_call(Method::POST, todo::<_, requests::Create>()) + self.do_call( + Method::POST, + |create::Args { + title, + slug, + description, + owner, + }| { + ( + "/authors".into(), + requests::Create { + title, + description, + slug, + owner, + }, + ) + }, + ) } fn update(&mut self) -> impl CallStep { - self.do_call(Method::PATCH, todo::<_, requests::Update>()) + self.do_call(Method::PATCH, |update::Args { author, update }| { + ( + format_compact!("/authors/{author}"), + requests::Update { + title: update.title, + description: update.description, + pfp: update.pfp, + slug: update.slug, + verified: update.verified, + }, + ) + }) } } diff --git a/http/src/client/games.rs b/http/src/client/games.rs index f3cafa9..ab6aa94 100644 --- a/http/src/client/games.rs +++ b/http/src/client/games.rs @@ -1,25 +1,97 @@ use super::*; -use viendesu_core::requests::games::{create, get, search, update}; +use viendesu_core::{ + requests::games::{create, get, search, update}, + types::game::Selector, +}; use crate::requests::games as requests; impl GamesRef for Hidden<'_> { fn get(&mut self) -> impl CallStep { - self.do_call(Method::GET, todo::<_, requests::Get>()) + self.do_call(Method::GET, |get::Args { game }| match game { + Selector::Id(id) => (format_compact!("/games/{}", id.to_str()), requests::Get {}), + Selector::FullyQualified(fq) => ( + format_compact!("/games/{}/{}", fq.author, fq.slug), + requests::Get {}, + ), + }) } fn search(&mut self) -> impl CallStep { - self.do_call(Method::POST, todo::<_, requests::Search>()) + self.do_call( + Method::POST, + |search::Args { + query, + author, + include, + exclude, + order, + sort_by, + limit, + }| { + ( + "/games/search".into(), + requests::Search { + query, + author, + include, + exclude, + order, + sort_by, + limit, + }, + ) + }, + ) } } impl GamesMut for Hidden<'_> { fn create(&mut self) -> impl CallStep { - self.do_call(Method::POST, todo::<_, requests::Create>()) + self.do_call( + Method::POST, + |create::Args { + title, + description, + thumbnail, + author, + slug, + vndb, + release_date, + }| { + ( + "/games".into(), + requests::Create { + title, + description, + thumbnail, + author, + slug, + vndb, + release_date, + }, + ) + }, + ) } fn update(&mut self) -> impl CallStep { - self.do_call(Method::PATCH, todo::<_, requests::Update>()) + self.do_call(Method::PATCH, |update::Args { id, update }| { + ( + format_compact!("/games/{id}"), + requests::Update { + title: update.title, + description: update.description, + slug: update.slug, + thumbnail: update.thumbnail, + genres: update.genres, + badges: update.badges, + tags: update.tags, + screenshots: update.screenshots, + published: update.published, + }, + ) + }) } } diff --git a/http/src/server/response/mod.rs b/http/src/server/response/mod.rs index 812e94e..f0ab89b 100644 --- a/http/src/server/response/mod.rs +++ b/http/src/server/response/mod.rs @@ -2,7 +2,7 @@ use axum::{ http::StatusCode, response::{IntoResponse, Response as AxumResponse}, }; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use crate::format::{DumpParams, Format}; use crate::requests::{IsResponse, status_code::HasStatusCode}; diff --git a/http/src/server/routes.rs b/http/src/server/routes.rs index 8c0bea7..8c0982a 100644 --- a/http/src/server/routes.rs +++ b/http/src/server/routes.rs @@ -174,11 +174,169 @@ fn users(router: RouterScope) -> RouterScope { } fn authors(router: RouterScope) -> RouterScope { + use crate::requests::authors::{Create, Get, Update}; + + use viendesu_core::{ + requests::authors::{create, get, update}, + service::authors::{AuthorsMut as _, AuthorsRef as _}, + types::author, + }; + router + .route( + "/", + post(async |mut session: SessionOf, ctx: Ctx| { + let Create { + title, + slug, + description, + owner, + } = ctx.request; + session + .authors_mut() + .create() + .call(create::Args { + title, + slug, + description, + owner, + }) + .await + }), + ) + .route( + "/{selector}", + get(async |mut session: SessionOf, mut ctx: Ctx| { + let author: author::Selector = ctx.path().await?; + let Get {} = ctx.request; + + session.authors().get().call(get::Args { author }).await + }), + ) + .route( + "/{selector}", + patch(async |mut session: SessionOf, mut ctx: Ctx| { + let author: author::Selector = ctx.path().await?; + let Update { + title, + description, + pfp, + slug, + verified, + } = ctx.request; + + session + .authors_mut() + .update() + .call(update::Args { + author, + update: update::Update { + title, + description, + pfp, + slug, + verified, + }, + }) + .await + }), + ) } fn games(router: RouterScope) -> RouterScope { + use crate::requests::games::{Create, Get, Search, Update}; + + use viendesu_core::{ + requests::games::{create, get, search, update}, + service::games::{GamesMut as _, GamesRef as _}, + types::{author, game}, + }; + router + .route( + "/", + post(async |mut session: SessionOf, ctx: Ctx| { + let Create { + title, + description, + thumbnail, + author, + slug, + vndb, + release_date, + } = ctx.request; + session + .games_mut() + .create() + .call(create::Args { + title, + description, + thumbnail, + author, + slug, + vndb, + release_date, + }) + .await + }), + ) + .route( + "/{game_id}", + get(async |mut session: SessionOf, mut ctx: Ctx| { + let game_id: game::Id = ctx.path().await?; + let Get {} = ctx.request; + + session + .games() + .get() + .call(get::Args { + game: game_id.into(), + }) + .await + }), + ) + .route( + "/{author}/{slug}", + get(async |mut session: SessionOf, mut ctx: Ctx| { + let (author, slug) = ctx.path::<(author::Selector, game::Slug)>().await?; + + session + .games() + .get() + .call(get::Args { + game: game::Selector::FullyQualified(game::FullyQualified { author, slug }), + }) + .await + }), + ) + .route( + "/search", + post(async |mut session: SessionOf, ctx: Ctx| { + let Search { + query, + author, + include, + exclude, + order, + sort_by, + limit, + } = ctx.request; + + session + .games() + .search() + .call(search::Args { + query, + author, + include, + exclude, + order, + sort_by, + limit, + }) + .await + }), + ) } fn boards(router: RouterScope) -> RouterScope {