+ } else if (std.mem.startsWith(u8, req.target, "/upvote/")) {
+ const login = logged_in orelse return error.NotLoggedIn;
+
+ const post_id_str = req.target[8..req.target.len];
+ const post_id: PostId = @enumFromInt(try std.fmt.parseUnsigned(u64, post_id_str, 10));
+
+ try Chirp.vote(env, post_id, login.user_id, .Up);
+
+ if (req.get_header("Referer")) |ref| {
+ try res.redirect(ref);
+ }
+ try res.send();
+ } else if (std.mem.startsWith(u8, req.target, "/downvote/")) {
+ const login = logged_in orelse return error.NotLoggedIn;
+
+ const post_id_str = req.target[10..req.target.len];
+ const post_id: PostId = @enumFromInt(try std.fmt.parseUnsigned(u64, post_id_str, 10));
+
+ try Chirp.vote(env, post_id, login.user_id, .Down);
+
+ if (req.get_header("Referer")) |ref| {
+ try res.redirect(ref);
+ }
+ try res.send();
+ } else if (std.mem.startsWith(u8, req.target, "/unupvote/")) {
+ // TODO: maybe move to one /unvote?
+ const login = logged_in orelse return error.NotLoggedIn;
+
+ const post_id_str = req.target[10..req.target.len];
+ const post_id: PostId = @enumFromInt(try std.fmt.parseUnsigned(u64, post_id_str, 10));
+
+ try Chirp.unvote(env, post_id, login.user_id);
+
+ if (req.get_header("Referer")) |ref| {
+ try res.redirect(ref);
+ }
+ try res.send();
+ } else if (std.mem.startsWith(u8, req.target, "/undownvote/")) {
+ const login = logged_in orelse return error.NotLoggedIn;
+
+ const post_id_str = req.target[12..req.target.len];
+ const post_id: PostId = @enumFromInt(try std.fmt.parseUnsigned(u64, post_id_str, 10));
+
+ try Chirp.unvote(env, post_id, login.user_id);
+
+ if (req.get_header("Referer")) |ref| {
+ try res.redirect(ref);
+ }
+ try res.send();