This commit is contained in:
Aleksandr 2025-12-22 21:59:51 +03:00
parent 843ae33a3f
commit 513826750b
11 changed files with 239 additions and 34 deletions

View file

@ -7,7 +7,7 @@ use crate::requests::authors as requests;
impl Authors for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, |get::Args { author }| {
(format_compact!("/authors/{author}"), requests::Get {})
(c!("/authors/{author}"), requests::Get {})
})
}
@ -21,7 +21,7 @@ impl Authors for HttpClient {
owner,
}| {
(
"/authors".into(),
c!("/authors"),
requests::Create {
title,
description,
@ -36,7 +36,7 @@ impl Authors for HttpClient {
fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err> {
self.do_call(Method::PATCH, |update::Args { author, update }| {
(
format_compact!("/authors/{author}"),
c!("/authors/{author}"),
requests::Update {
title: update.title,
description: update.description,

View file

@ -9,13 +9,22 @@ use crate::requests::games as requests;
impl Games for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
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 {},
),
})
self.do_call(
Method::GET,
|get::Args {
game,
resolve_marks,
}| match game {
Selector::Id(id) => (
c!("/games/{}", id.to_str()),
requests::Get { resolve_marks },
),
Selector::FullyQualified(fq) => (
c!("/games/{}/{}", fq.author, fq.slug),
requests::Get { resolve_marks },
),
},
)
}
fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err> {
@ -81,7 +90,7 @@ impl Games for HttpClient {
fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err> {
self.do_call(Method::PATCH, |update::Args { id, update }| {
(
format_compact!("/games/{id}"),
c!("/games/{id}"),
requests::Update {
title: update.title,
description: update.description,

View file

@ -2,7 +2,7 @@ use std::sync::Arc;
use eva::{
error::ShitHappens,
str::{CompactString, format_compact},
str::{CompactString, format_compact as c},
};
use http::Method;
@ -17,6 +17,7 @@ use viendesu_core::{
games::Games,
marks::{Badges, Genres, Tags},
messages::Messages,
tabs::Tabs,
threads::Threads,
users::Users,
},
@ -36,6 +37,7 @@ mod games;
mod users;
mod marks;
mod tabs;
struct DoRequest<'c, P> {
client: &'c mut HttpClient,
@ -116,11 +118,11 @@ impl HttpClient {
.client
.execute(req.build().expect("shit happens"))
.await
.map_err(|e| Aux::InternalError(format_compact!("failed to make request: {e:#}")))?;
.map_err(|e| Aux::InternalError(c!("failed to make request: {e:#}")))?;
let bytes = response
.bytes()
.await
.map_err(|e| Aux::InternalError(format_compact!("failed to read bytes: {e:#}")))?;
.map_err(|e| Aux::InternalError(c!("failed to read bytes: {e:#}")))?;
#[derive(serde::Deserialize)]
#[serde(untagged)]

49
http/src/client/tabs.rs Normal file
View file

@ -0,0 +1,49 @@
use super::*;
use crate::requests::tabs;
use viendesu_core::requests::tabs::{delete, insert, list, list_items};
impl Tabs for HttpClient {
fn list(&mut self) -> impl CallStep<list::Args, Ok = list::Ok, Err = list::Err> {
self.do_call(Method::GET, |list::Args { user }| {
(c!("/users/{user}/tabs"), tabs::List {})
})
}
fn list_items(
&mut self,
) -> impl CallStep<list_items::Args, Ok = list_items::Ok, Err = list_items::Err> {
self.do_call(
Method::GET,
|list_items::Args {
tab,
user,
start_from,
limit,
resolve_marks,
}| {
(
c!("/users/{user}/tabs/{tab}"),
tabs::ListItems {
resolve_marks,
start_from,
limit,
},
)
},
)
}
fn insert(&mut self) -> impl CallStep<insert::Args, Ok = insert::Ok, Err = insert::Err> {
self.do_call(Method::POST, |insert::Args { user, tab, item }| {
(c!("/users/{user}/tabs/{tab}"), tabs::Insert { item })
})
}
fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err> {
self.do_call(Method::DELETE, |delete::Args { user, tab, item }| {
(c!("/users/{user}/tabs/{tab}/{item}"), tabs::Delete {})
})
}
}

View file

@ -1,7 +1,5 @@
use super::*;
use eva::str::format_compact;
use viendesu_core::requests::users::{
begin_auth, check_auth, confirm_sign_up, finish_auth, get, sign_in, sign_up, update,
};
@ -11,7 +9,7 @@ use crate::requests::users as requests;
impl Users for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, |get::Args { user }| match user {
Some(u) => (format_compact!("/users/{u}"), requests::Get {}),
Some(u) => (c!("/users/{u}"), requests::Get {}),
None => ("/users/me".into(), requests::Get {}),
})
}
@ -37,7 +35,7 @@ impl Users for HttpClient {
) -> impl CallStep<finish_auth::Args, Ok = finish_auth::Ok, Err = finish_auth::Err> {
self.do_call(Method::POST, |finish_auth::Args { auth_session }| {
(
format_compact!("/users/finish-auth/{auth_session}"),
c!("/users/finish-auth/{auth_session}"),
requests::FinishAuth {},
)
})
@ -52,10 +50,7 @@ impl Users for HttpClient {
fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err> {
self.do_call(Method::PATCH, |update::Args { user, update }| match user {
Some(u) => (
format_compact!("/users/{u}"),
requests::Update::from(update),
),
Some(u) => (c!("/users/{u}"), requests::Update::from(update)),
None => ("/users/me".into(), requests::Update::from(update)),
})
}

View file

@ -48,7 +48,10 @@ status_code::direct!(reqs::search::Ok => OK);
status_code::map!(reqs::search::Err => [NoSuchAuthor]);
#[data]
pub struct Get {}
pub struct Get {
#[serde(default)]
pub resolve_marks: bool,
}
impl_req!(Get => [reqs::get::Ok; reqs::get::Err]);

View file

@ -25,6 +25,7 @@ macro_rules! impl_req {
}
pub mod marks;
pub mod tabs;
pub mod users;
pub mod authors;

53
http/src/requests/tabs.rs Normal file
View file

@ -0,0 +1,53 @@
use eva::data;
use viendesu_core::{errors, requests::tabs as reqs, types::entity};
use crate::requests::status_code;
#[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 => [InvalidItemId, NoSuchItem, NoSuchTab]);
#[data]
pub struct Insert {
pub item: entity::Id,
}
impl_req!(Insert => [reqs::insert::Ok; reqs::insert::Err]);
status_code::direct!(reqs::insert::Ok => CREATED);
status_code::map!(reqs::insert::Err => [Duplicate, InvalidKind, NoSuchTab, InvalidItemId]);
#[data]
pub struct ListItems {
#[serde(default)]
pub resolve_marks: bool,
#[serde(default)]
pub start_from: Option<entity::Id>,
#[serde(default)]
pub limit: reqs::list_items::Limit,
}
impl_req!(ListItems => [reqs::list_items::Ok; reqs::list_items::Err]);
status_code::direct!(reqs::list_items::Ok => OK);
status_code::map!(reqs::list_items::Err => [InvalidItemId, NoSuchTab]);
#[data]
pub struct List {}
impl_req!(List => [reqs::list::Ok; reqs::list::Err]);
status_code::direct!(reqs::list::Ok => OK);
status_code::map!(reqs::list::Err => [NotFound]);
const _: () = {
use errors::tabs::*;
use status_code::direct;
direct!(InvalidKind => BAD_REQUEST);
direct!(Duplicate => BAD_REQUEST);
direct!(InvalidItemId => BAD_REQUEST);
direct!(NoSuchTab => NOT_FOUND);
direct!(NoSuchItem => NOT_FOUND);
};

View file

@ -169,6 +169,15 @@ where
Handler::patch(load_args::<R>).exec(make_request)
}
pub fn delete<R, T, M>(make_request: M) -> FinishedHandler<R, M, T, impl MakeContext<R>>
where
R: ServerRequest,
T: Types,
M: MakeRequest<T, R>,
{
Handler::delete(load_args::<R>).exec(make_request)
}
pub struct Handler<R: ServerRequest, Cx>(Inner<R, Cx>);
impl<R: ServerRequest, Cx: MakeContext<R>> Handler<R, Cx> {
@ -196,6 +205,14 @@ impl<R: ServerRequest, Cx: MakeContext<R>> Handler<R, Cx> {
})
}
pub fn delete(make_context: Cx) -> Handler<R, Cx> {
Self(Inner {
make_context,
method: MethodFilter::DELETE,
_phantom: PhantomData,
})
}
pub fn exec<T, M>(self, make_request: M) -> FinishedHandler<R, M, T, Cx>
where
T: Types,

View file

@ -1,7 +1,7 @@
use crate::server::{
Types,
context::Context as Ctx,
handler::{RouterScope, get, patch, post},
handler::{RouterScope, delete, get, patch, post},
};
use viendesu_core::{
@ -113,7 +113,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
requests::users::{
begin_auth, check_auth, confirm_sign_up, finish_auth, get, sign_in, sign_up, update,
},
service::users::Users,
service::{tabs::Tabs, users::Users},
};
fn convert_update(u: Update) -> update::Update {
@ -253,6 +253,72 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
},
),
)
.nest("/{user}/tabs", |router| {
use crate::requests::tabs::{Delete, Insert, List, ListItems};
use viendesu_core::requests::tabs::{delete, insert, list, list_items};
router
.route(
"/",
get(async |mut session: SessionOf<T>, mut ctx: Ctx<List>| {
let user = ctx.path().await?;
let List {} = ctx.request;
session.tabs().list().call(list::Args { user }).await
}),
)
.nest("/{tab}", |router| {
router
.route(
"/{item}",
delete(async |mut session: SessionOf<T>, mut ctx: Ctx<Delete>| {
let (user, tab, item) = ctx.path().await?;
let Delete {} = ctx.request;
session
.tabs()
.delete()
.call(delete::Args { user, tab, item })
.await
}),
)
.route(
"/",
post(async |mut session: SessionOf<T>, mut ctx: Ctx<Insert>| {
let (user, tab) = ctx.path().await?;
let Insert { item } = ctx.request;
session
.tabs()
.insert()
.call(insert::Args { user, tab, item })
.await
}),
)
.route(
"/",
get(async |mut session: SessionOf<T>, mut ctx: Ctx<ListItems>| {
let (user, tab) = ctx.path().await?;
let ListItems {
resolve_marks,
start_from,
limit,
} = ctx.request;
session
.tabs()
.list_items()
.call(list_items::Args {
tab,
user,
start_from,
limit,
resolve_marks,
})
.await
}),
)
})
})
}
fn uploads<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
@ -378,13 +444,14 @@ fn games<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
"/{game_id}",
get(async |mut session: SessionOf<T>, mut ctx: Ctx<Get>| {
let game_id: game::Id = ctx.path().await?;
let Get {} = ctx.request;
let Get { resolve_marks } = ctx.request;
session
.games()
.get()
.call(get::Args {
game: game_id.into(),
resolve_marks,
})
.await
}),
@ -393,11 +460,13 @@ fn games<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
"/{author}/{slug}",
get(async |mut session: SessionOf<T>, mut ctx: Ctx<Get>| {
let (author, slug) = ctx.path::<(author::Selector, game::Slug)>().await?;
let Get { resolve_marks } = ctx.request;
session
.games()
.get()
.call(get::Args {
resolve_marks,
game: game::Selector::FullyQualified(game::FullyQualified { author, slug }),
})
.await