diff --git a/Cargo.lock b/Cargo.lock index 161a0fe..3cfbda4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -467,6 +467,7 @@ dependencies = [ "serde", "serde_json", "sha3", + "urlencoding", "worker", "worker-kv 0.8.0", ] @@ -879,6 +880,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index a59dbe4..e2040d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ pulldown-cmark = "0.12" cron-parser = "0.9" chrono = "0.4" chrono-tz = { version = "0.10", features = ["serde"] } +urlencoding = "2" [profile.release] opt-level = "s" diff --git a/README.md b/README.md index 3cd1bce..e22f59d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1 @@ Register for you next game. - -- TODO: schedule next games diff --git a/src/lib.rs b/src/lib.rs index 5d875cd..9fdf512 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,8 @@ struct Game { // see Team struct comment players: HashMap, guests: Vec, - // TODO: comments?? + #[serde(default)] + comments: Vec, } struct AppCtx { @@ -70,6 +71,9 @@ async fn main(req: Request, env: Env, _: Context) -> Result { .post_async("/team/:teamkey/new_game", new_game) .post_async("/team/:teamkey/player/:playerid/play", play) .post_async("/team/:teamkey/player/:playerid/not_play", not_play) + .post_async("/team/:teamkey/comment", add_comment) + .post_async("/team/:teamkey/guest", add_guest) + .post_async("/team/:teamkey/guest/:guest/delete", delete_guest) .run(req, env) .await } @@ -433,7 +437,6 @@ async fn team(_: Request, ctx: RouteContext) -> Result { options.insert(Options::ENABLE_GFM); let parser = Parser::new_ext(&ng.description, options); - // Write to String buffer. let mut html_output = String::new(); pulldown_cmark::html::push_html(&mut html_output, parser); html_output @@ -443,6 +446,7 @@ async fn team(_: Request, ctx: RouteContext) -> Result { .render(mjctx! { team_name => team.name, key, + ng_key, ng, description, playing_count, @@ -484,6 +488,7 @@ async fn new_game(req: Request, ctx: RouteContext) -> Result { description, players: team.players.iter().map(|(k, _)| (k.to_string(), false)).collect(), guests: Vec::new(), + comments: Vec::new(), }; let ng_key = random::hex_string(); @@ -612,3 +617,155 @@ async fn not_play(req: Request, ctx: RouteContext) -> Result { Response::error("game not found", 404) } } + +async fn add_comment(req: Request, ctx: RouteContext) -> Result { + let key = ctx.param("teamkey").unwrap(); + + let teams_kv = ctx.kv("teams")?; + let games_kv = ctx.kv("games")?; + + let team: Team = { + let t = teams_kv.get(key).text().await?; + if t.is_none() { + return Response::error("team not found", 404); + } + let t = t.unwrap(); + serde_json::from_str(&t).unwrap() + }; + + if let Some(ng_key) = team.next_game { + let mut ng: Game = { + let g = games_kv.get(&ng_key).text().await?; + if g.is_none() { + return Response::error("game does not exist anymore", 404); + } + let g = g.unwrap(); + serde_json::from_str(&g).unwrap() + }; + + let mut r = req.clone_mut()?; + let f = r.form_data().await?; + let comment = f.get_field("comment").unwrap_or_default(); + if comment.len() == 0 { + return Response::error("comment can't be empty", 400); + } + + ng.comments.push(comment); + + match games_kv + .put(&ng_key, serde_json::to_string(&ng).unwrap())? + .execute() + .await + { + Ok(_) => { + let mut team_link = req.url()?.clone(); + team_link.set_path(&format!("/team/{}", key)); + + Response::redirect(team_link) + } + Err(_) => Response::error("failed to set play", 500), + } + } else { + Response::error("game not found", 404) + } +} + +async fn add_guest(req: Request, ctx: RouteContext) -> Result { + let key = ctx.param("teamkey").unwrap(); + + let teams_kv = ctx.kv("teams")?; + let games_kv = ctx.kv("games")?; + + let team: Team = { + let t = teams_kv.get(key).text().await?; + if t.is_none() { + return Response::error("team not found", 404); + } + let t = t.unwrap(); + serde_json::from_str(&t).unwrap() + }; + + if let Some(ng_key) = team.next_game { + let mut ng: Game = { + let g = games_kv.get(&ng_key).text().await?; + if g.is_none() { + return Response::error("game does not exist anymore", 404); + } + let g = g.unwrap(); + serde_json::from_str(&g).unwrap() + }; + + let mut r = req.clone_mut()?; + let f = r.form_data().await?; + let guests = f.get_field("guest_name").unwrap_or_default(); + if guests.len() == 0 { + return Response::error("guest_name can't be empty", 400); + } + + guests.trim().split(',').for_each(|g| ng.guests.push(g.to_string())); + + match games_kv + .put(&ng_key, serde_json::to_string(&ng).unwrap())? + .execute() + .await + { + Ok(_) => { + let mut team_link = req.url()?.clone(); + team_link.set_path(&format!("/team/{}", key)); + + Response::redirect(team_link) + } + Err(_) => Response::error("failed to set play", 500), + } + } else { + Response::error("game not found", 404) + } +} + +async fn delete_guest(req: Request, ctx: RouteContext) -> Result { + let key = ctx.param("teamkey").unwrap(); + + let teams_kv = ctx.kv("teams")?; + let games_kv = ctx.kv("games")?; + + let team: Team = { + let t = teams_kv.get(key).text().await?; + if t.is_none() { + return Response::error("team not found", 404); + } + let t = t.unwrap(); + serde_json::from_str(&t).unwrap() + }; + + if let Some(ng_key) = team.next_game { + let mut ng: Game = { + let g = games_kv.get(&ng_key).text().await?; + if g.is_none() { + return Response::error("game does not exist anymore", 404); + } + let g = g.unwrap(); + serde_json::from_str(&g).unwrap() + }; + + let g = urlencoding::decode(ctx.param("guest").unwrap()).unwrap().to_string(); + + // TODO: only delete 1 guest + ng.guests = ng.guests.into_iter().filter(|gg| *gg != g).collect(); + + match games_kv + .put(&ng_key, serde_json::to_string(&ng).unwrap())? + .execute() + .await + { + Ok(_) => { + let mut team_link = req.url()?.clone(); + team_link.set_path(&format!("/team/{}", key)); + + Response::redirect(team_link) + } + Err(_) => Response::error("failed to set play", 500), + } + } else { + Response::error("game not found", 404) + } +} diff --git a/templates/team.html b/templates/team.html index 33e57ca..b116e56 100644 --- a/templates/team.html +++ b/templates/team.html @@ -19,24 +19,54 @@

-
-
- {{ description|safe }} -
-
- -
-

- {{ playing_count }} players playing! -

+
+
+
+

{{ playing_count }} playing!

+ {% if ng.guests %} +

including {{ ng.guests|length }} guests

+ {% endif %} +
+ + {{ description|safe }} + +
+
+
+
+
+

Comments

+ {% for comment in ng.comments %} +
{{ comment }}
+ {% endfor %} +
+
+
+ +
+
+
+
+ +
+
+
+
+
-
+
+ + + + - + @@ -66,6 +96,58 @@

Player Click to toggle
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ + {% if ng.guests %} +
+ + + + + + + + + + + + + {% for name in ng.guests %} + + + + + {% endfor %} + +
GuestAction
+ {{ name }} + +
+ +
+
+
+ {% endif %}
{% else %}