This commit is contained in:
Daan Vanoverloop 2022-09-16 14:22:40 +02:00
parent c1a61d28a4
commit 0b9318b5c4
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
10 changed files with 63 additions and 33 deletions

View File

@ -21,7 +21,7 @@ pub async fn apply_outcome(outcome: &EventOutcome, db: &Connection<Db>) -> Resul
for (player, reward) in outcome.points.iter() { for (player, reward) in outcome.points.iter() {
db.users() db.users()
.update_one( .update_one(
doc! { "id": player.to_string() }, doc! { "name": player.to_string() },
doc! { "$inc": { "score": reward } }, doc! { "$inc": { "score": reward } },
None, None,
) )

View File

@ -1,4 +1,10 @@
use rocket::{http::Status, response, response::Responder, Request}; use std::borrow::Borrow;
use rocket::{
http::Status,
response::{self, status, Responder},
Request,
};
use rocket_db_pools::mongodb; use rocket_db_pools::mongodb;
use rocket_okapi::response::OpenApiResponderInner; use rocket_okapi::response::OpenApiResponderInner;
use schemars::JsonSchema; use schemars::JsonSchema;
@ -30,7 +36,7 @@ impl ToString for Ordering {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum PartyError { pub enum PartyError {
#[error("internal error {source:?}")] #[error("{source}")]
CoreError { CoreError {
#[from] #[from]
source: CoreError, source: CoreError,
@ -68,13 +74,16 @@ impl OpenApiResponderInner for PartyError {
impl<'r, 'o: 'r> Responder<'r, 'o> for PartyError { impl<'r, 'o: 'r> Responder<'r, 'o> for PartyError {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> { fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
println!("{:#?}", &self); println!("{}", self.to_string());
let message = self.to_string();
match self { match self {
Self::CoreError { source } => match source { Self::CoreError { source } => match source {
CoreError::UserNotFound(_) | CoreError::EventNotFound(_) => Status::NotFound, CoreError::UserNotFound(_) | CoreError::EventNotFound(_) => {
_ => Status::InternalServerError, (Status::NotFound, "not found".to_string())
}
_ => (Status::BadRequest, message),
}, },
_ => Status::InternalServerError, _ => (Status::InternalServerError, "unknown error".to_string()),
} }
.respond_to(req) .respond_to(req)
} }

View File

@ -471,11 +471,18 @@ where
T: FromStr + ToString + Default + Clone + PartialEq, T: FromStr + ToString + Default + Clone + PartialEq,
{ {
fn edit(cx: Scope<'a>, props: EditProps<'a, WithContext<Ctx, T>>) -> View<G> { fn edit(cx: Scope<'a>, props: EditProps<'a, WithContext<Ctx, T>>) -> View<G> {
let ctx = use_context::<Ctx>(cx);
let value = create_signal(cx, props.state.get_untracked().to_string()); let value = create_signal(cx, props.state.get_untracked().to_string());
let ctx = use_context::<Ctx>(cx); create_effect(cx, move || {
if value.get_untracked().is_empty() {
if let Some(first) = ctx.options(cx).get().get(0) {
value.set(first.to_string());
}
}
});
create_effect(cx, || { create_effect(cx, move || {
props props
.state .state
.set((*value.get()).parse::<T>().unwrap_or(T::default()).into()) .set((*value.get()).parse::<T>().unwrap_or(T::default()).into())

View File

@ -150,7 +150,7 @@ macro_rules! events {
impl EventSpec { impl EventSpec {
pub fn create_event(self) -> Result<Event, PartyError> { pub fn create_event(self) -> Result<Event, PartyError> {
if self.name.is_empty() { if self.name.is_empty() {
return Err(PartyError::Unknown("invalid name".into())) return Err(PartyError::Other("invalid name".into()))
} }
let event_type = match self.event_type { let event_type = match self.event_type {
@ -176,7 +176,7 @@ macro_rules! events {
$((EventType::$name(s), EventUpdate::$name(u)) => { $((EventType::$name(s), EventUpdate::$name(u)) => {
s.apply_update(u) s.apply_update(u)
})* })*
_ => Err(PartyError::Unknown("invalid update".into())), _ => Err(PartyError::Other("invalid update: update type does not match event type".into())),
} }
} }
@ -524,19 +524,19 @@ pub mod free_for_all_game {
match update { match update {
FreeForAllGameUpdate::SetRanking(r) => { FreeForAllGameUpdate::SetRanking(r) => {
if !r.is_valid(&self.spec.participants) { if !r.is_valid(&self.spec.participants) {
return Err(PartyError::Unknown("invalid ranking, all participants mentioned in ranking must be participating".into())); return Err(PartyError::Other("invalid ranking, all participants mentioned in ranking must be participating".into()));
} }
self.ranking = Some(r) self.ranking = Some(r)
} }
FreeForAllGameUpdate::ScoreDelta(d) => match &mut self.ranking { FreeForAllGameUpdate::ScoreDelta(d) => match &mut self.ranking {
Some(Ranking::Ranking(_)) | None => { Some(Ranking::Ranking(_)) => {
return Err(PartyError::Unknown("cannot apply score delta".into())) return Err(PartyError::Other("cannot apply score delta".into()))
} }
None => self.ranking = Some(Ranking::Scores(d)),
Some(Ranking::Scores(s)) => { Some(Ranking::Scores(s)) => {
for (participant, delta) in d.iter() { for (participant, delta) in d.iter() {
if let Some(value) = s.get(participant) { let value = s.get(participant).unwrap_or(&0);
s.insert(participant.clone(), value + delta); s.insert(participant.clone(), value + delta);
}
} }
} }
}, },
@ -553,7 +553,7 @@ pub mod free_for_all_game {
.unwrap_or(true) .unwrap_or(true)
{ {
self.spec.participants.insert(name); self.spec.participants.insert(name);
return Err(PartyError::Unknown("cannot remove participant, all participants mentioned in ranking must be participating".into())); return Err(PartyError::Other("cannot remove participant, all participants mentioned in ranking must be participating".into()));
} }
} }
FreeForAllGameUpdate::SetParticipants(participants) => { FreeForAllGameUpdate::SetParticipants(participants) => {
@ -563,7 +563,7 @@ pub mod free_for_all_game {
.map(|r| r.is_valid(&participants)) .map(|r| r.is_valid(&participants))
.unwrap_or(true) .unwrap_or(true)
{ {
return Err(PartyError::Unknown("invalid list of participants, all participants mentioned in ranking must be participating".into())); return Err(PartyError::Other("invalid list of participants, all participants mentioned in ranking must be participating".into()));
} }
self.spec.participants = participants; self.spec.participants = participants;
} }

View File

@ -18,8 +18,8 @@ pub enum PartyError {
UserNotFound(String), UserNotFound(String),
#[error("event `{0}` does not exist")] #[error("event `{0}` does not exist")]
EventNotFound(String), EventNotFound(String),
#[error("unknown error: {0}")] #[error("{0}")]
Unknown(String), Other(String),
#[error("invalid parameter: {0}")] #[error("invalid parameter: {0}")]
InvalidParameter(String), InvalidParameter(String),
} }

View File

@ -634,8 +634,6 @@ pub fn web_edit(tokens: TokenStream) -> TokenStream {
} }
}; };
println!("{}", &res.to_string());
TokenStream::from(res) TokenStream::from(res)
} }
@ -703,7 +701,5 @@ pub fn web_view(tokens: TokenStream) -> TokenStream {
} }
}; };
println!("{}", &res.to_string());
TokenStream::from(res) TokenStream::from(res)
} }

6
web/dist/index.html vendored
View File

@ -6,7 +6,7 @@
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
<title>LAN Party</title> <title>LAN Party</title>
<link rel="preload" href="/index-495632ef4eca1348_bg.wasm" as="fetch" type="application/wasm" crossorigin=""> <link rel="preload" href="/index-1e8437b6157bd12b_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="/index-495632ef4eca1348.js"></head> <link rel="modulepreload" href="/index-1e8437b6157bd12b.js"></head>
<body> <body>
<script type="module">import init from '/index-495632ef4eca1348.js';init('/index-495632ef4eca1348_bg.wasm');</script></body></html> <script type="module">import init from '/index-1e8437b6157bd12b.js';init('/index-1e8437b6157bd12b_bg.wasm');</script></body></html>

View File

@ -41,6 +41,7 @@ pub fn EventsPage<'a, G: Html>(cx: Scope<'a>) -> View<G> {
let event_outcome = create_signal(cx, EventOutcome::default()); let event_outcome = create_signal(cx, EventOutcome::default());
let events = use_context::<Events>(cx); let events = use_context::<Events>(cx);
let users = use_context::<Users>(cx);
let dispatch = move |msg: Msg| { let dispatch = move |msg: Msg| {
spawn_local_scoped(cx, async move { spawn_local_scoped(cx, async move {
@ -84,10 +85,8 @@ pub fn EventsPage<'a, G: Html>(cx: Scope<'a>) -> View<G> {
.and_then(|inner| inner.ok_or(anyhow!("missing body"))); .and_then(|inner| inner.ok_or(anyhow!("missing body")));
if let Ok(outcome) = res { if let Ok(outcome) = res {
debug!("{:#?}", outcome);
event_outcome.set(outcome); event_outcome.set(outcome);
} else { } else {
debug!("oh no");
messenger.add_result( messenger.add_result(
res, res,
Option::<String>::None, Option::<String>::None,
@ -95,7 +94,22 @@ pub fn EventsPage<'a, G: Html>(cx: Scope<'a>) -> View<G> {
) )
} }
} }
_ => {} Msg::Stop(event_name) => {
let res = api_request::<(), EventOutcome>(
Method::POST,
&format!("/event/{}/stop", event_name),
None,
)
.await;
messenger.add_result(
res,
Some("Event finished, scores were applied"),
Some("Unable to finish event"),
);
let _ = users.load();
}
} }
}); });
}; };

View File

@ -100,7 +100,7 @@ pub trait EventsExt {
impl EventsExt for Events { impl EventsExt for Events {
async fn load(&self) -> Result<()> { async fn load(&self) -> Result<()> {
self.0.set( self.0.set(
api_request::<_, Vec<Event>>(Method::GET, "/event", Option::<()>::None) api_request::<_, Vec<Event>>(Method::GET, "/event?concluded=false", Option::<()>::None)
.await .await
.and_then(|inner| inner.ok_or(anyhow!("missing body")))?, .and_then(|inner| inner.ok_or(anyhow!("missing body")))?,
); );

View File

@ -40,7 +40,11 @@ pub async fn api_request<B: Serialize, R: for<'a> Deserialize<'a>>(
Ok(None) Ok(None)
} }
} else { } else {
Err(anyhow!("Request failed")) if let Ok(text) = res.text().await {
Err(anyhow!("Request failed: {}", text.to_string()))
} else {
Err(anyhow!("Request failed"))
}
} }
} }