Compare commits

...

3 commits

Author SHA1 Message Date
b7e625dd98 Start ratings
This is actually fantastic, I'm really happy with how this has worked so far. My only concern for the future is how posting reviews from the `/ratings` path might work, since it's currently designed around posting reviews from the song page itself, but I think some HTMX and/or JS wil alleviate any problems I run into
2025-06-23 10:18:17 -04:00
f292368947 Song name in url string 2025-06-23 10:15:17 -04:00
93da50652a Remove unnecessary else 2025-06-23 10:14:25 -04:00
5 changed files with 49 additions and 8 deletions

View file

@ -38,7 +38,6 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
if (artists.len > 1) return request.redirect("http://127.0.0.1:8080", .found); if (artists.len > 1) return request.redirect("http://127.0.0.1:8080", .found);
break :blk artists[0].id; break :blk artists[0].id;
}, },
else => unreachable,
}; };
var root = try request.data(.object); var root = try request.data(.object);

View file

@ -0,0 +1,12 @@
const std = @import("std");
const jetzig = @import("jetzig");
pub fn post(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
const params = try request.params();
const id = params.getT(.integer, "song_id");
const review = params.getT(.string, "review");
try root.put("song_id", id);
try root.put("review", review);
return request.render(.created);
}

View file

@ -0,0 +1,2 @@
{{.song_id}}
{{.review}}

View file

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const jetzig = @import("jetzig"); const jetzig = @import("jetzig");
const queries = @import("../../queries.zig"); const queries = @import("../../queries.zig");
const decode = @import("../../date_fmt.zig").urlDecode;
pub fn index(request: *jetzig.Request) !jetzig.View { pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object); var root = try request.data(.object);
@ -20,21 +21,43 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
} }
pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View { pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
const parse_err = blk: {
const rdr_id = std.fmt.parseInt(i64, id, 10) catch |err| break :blk err;
const song = try jetzig.database.Query(.Song).find(rdr_id).execute(request.repo);
if (song == null) break :blk error.InvalidCharacter;
var name = std.ArrayList(u8).init(request.allocator);
try name.appendSlice("http://127.0.0.1:8080/songs/");
try name.appendSlice(song.?.name);
return request.redirect(try name.toOwnedSlice(), .found);
};
const id_int = switch (parse_err) {
error.Overflow => return request.fail(.not_found),
error.InvalidCharacter => blk: {
const rn = try decode(request.allocator, id);
std.log.debug("{s}", .{rn});
const songs = try jetzig.database.Query(.Song).where(.{ .name = rn }).all(request.repo);
if (songs.len == 0) return request.fail(.not_found);
if (songs.len > 1) return request.redirect("http://127.0.0.1:8080", .found);
break :blk songs[0].id;
},
};
var root = try request.data(.object); var root = try request.data(.object);
const song = try queries.entityQueryResult(request, queries.loadQuery(.song, .entity_info), .{id}); const song = try queries.entityQueryResult(request, queries.loadQuery(.song, .entity_info), .{id_int});
try root.put("song", song); try root.put("song", song);
const scrobbles = try queries.entityQueryResult(request, queries.loadQuery(.song, .get_scrobbles), .{id}); const scrobbles = try queries.entityQueryResult(request, queries.loadQuery(.song, .get_scrobbles), .{id_int});
try root.put("scrobbles", scrobbles); try root.put("scrobbles", scrobbles);
const albums = try queries.entityQueryResult(request, queries.loadQuery(.song, .get_albums), .{id}); const albums = try queries.entityQueryResult(request, queries.loadQuery(.song, .get_albums), .{id_int});
try root.put("albums", albums); try root.put("albums", albums);
const firstlast = try queries.entityQueryResult(request, queries.loadQuery(.song, .firstlast), .{id}); const firstlast = try queries.entityQueryResult(request, queries.loadQuery(.song, .firstlast), .{id_int});
try root.put("firstlast", firstlast); try root.put("firstlast", firstlast);
const timescale = try queries.entityQueryResult(request, queries.loadQuery(.song, .timescale), .{id}); const timescale = try queries.entityQueryResult(request, queries.loadQuery(.song, .timescale), .{id_int});
try root.put("yearly", timescale); try root.put("yearly", timescale);
return request.render(.ok); return request.render(.ok);
} }

View file

@ -5,6 +5,7 @@
<html> <html>
<head> <head>
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.5/dist/htmx.min.js" integrity="sha384-t4DxZSyQK+0Uv4jzy5B0QyHyWQD2GFURUmxKMBVww9+e2EJ0ei/vCvv7+79z0fkr" crossorigin="anonymous"></script>
<meta charset="UTF-8"> <meta charset="UTF-8">
</head> </head>
<body> <body>
@ -24,9 +25,13 @@
</div> </div>
<div style="display:flex;flex-direction:column;align-self:right"> <div style="display:flex;flex-direction:column;align-self:right">
<h2>Rating</h2> <h2>Rating</h2>
<input type="text"> <form>
<input type="button"> <input type="number" name="score" id="score" style="width:50px;height:30px">
<textarea name="review" id="review" style="width:350px;height:100px"></textarea>
<button hx-post="/ratings/songs" hx-vals='{"song_id":"{{.song.song_id}}"}' hx-target="#review-container" style="width:50px;height:30px">Post</button>
</form>
</div> </div>
<div id="review-container">No reviews</div>
</div> </div>
</body> </body>
</html> </html>