From 6f6aaecb8faeff5bc39e161b931404957fd43957 Mon Sep 17 00:00:00 2001 From: mitteneer Date: Mon, 23 Jun 2025 16:50:13 -0400 Subject: [PATCH] Create rating interface on songs view If no ratings are present, provide a textbox to make a rating. If a rating is present, show the rating. Eventually, there will be a button that allows an additional rating to be made, and the ability to delete ratings --- src/app/views/ratings/songs.zig | 6 ++++-- src/app/views/ratings/songs/post.zmpl | 3 +-- src/app/views/songs.zig | 4 ++++ src/app/views/songs/get.zmpl | 13 +++++++++++-- src/queries.zig | 15 ++++++++++++++- src/types.zig | 2 ++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/app/views/ratings/songs.zig b/src/app/views/ratings/songs.zig index 3145fb4..e77c2ac 100644 --- a/src/app/views/ratings/songs.zig +++ b/src/app/views/ratings/songs.zig @@ -3,9 +3,11 @@ 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 id = params.getT(.integer, "song_id").?; + const score = if (params.getT(.integer, "score")) |score| @as(i16, @truncate(score)) else null; const review = params.getT(.string, "review"); - try root.put("song_id", id); + try jetzig.database.Query(.Songrating).insert(.{ .song = id, .rating = score, .rating_text = review, .date = @divFloor(request.start_time, 1_000) }).execute(request.repo); + try root.put("score", score); try root.put("review", review); return request.render(.created); diff --git a/src/app/views/ratings/songs/post.zmpl b/src/app/views/ratings/songs/post.zmpl index 3366a0c..ca54fd7 100644 --- a/src/app/views/ratings/songs/post.zmpl +++ b/src/app/views/ratings/songs/post.zmpl @@ -1,2 +1 @@ -{{.song_id}} -{{.review}} \ No newline at end of file + {{.score}}: {{.review}} (Today) \ No newline at end of file diff --git a/src/app/views/songs.zig b/src/app/views/songs.zig index 00ec085..2f1772b 100644 --- a/src/app/views/songs.zig +++ b/src/app/views/songs.zig @@ -59,5 +59,9 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View { const timescale = try queries.entityQueryResult(request, queries.loadQuery(.song, .timescale), .{id_int}); try root.put("yearly", timescale); + + const ratings = try queries.entityQueryResult(request, queries.loadQuery(.song, .get_ratings), .{id_int}); + try root.put("reviews", ratings); + return request.render(.ok); } diff --git a/src/app/views/songs/get.zmpl b/src/app/views/songs/get.zmpl index 33e6886..f07b03c 100644 --- a/src/app/views/songs/get.zmpl +++ b/src/app/views/songs/get.zmpl @@ -1,6 +1,7 @@ @zig { const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date}; const columns: ColumnChoices = &.{.song, .artistlist, .album, .date}; + const reviews = try zmpl.coerceArray(".reviews"); } @@ -25,13 +26,21 @@

Rating

+
+ @zig { + if (reviews.len == 0) {
-
-
No reviews
+ } else { + for (reviews) |review| { + {{review.score}}: {{review.review}} ({{review.date}}) + } +} + } +
\ No newline at end of file diff --git a/src/queries.zig b/src/queries.zig index fcc5f07..0c9359e 100644 --- a/src/queries.zig +++ b/src/queries.zig @@ -42,6 +42,8 @@ pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args: .artistlist = if (artist_list.getLastOrNull()) |_| try artist_list.toOwnedSlice() else null, .scrobbles = if (entity.scrobbles) |scrobbles| scrobbles else null, .date = if (entity.date) |date| date else null, + .score = if (entity.score) |score| score else null, + .review = if (entity.review) |review| review else null, }); } @@ -49,7 +51,7 @@ pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args: } const EntityType = enum { scrobble, song, album, artist }; -const QueryTypeEnum = enum { firstlast, timescale, entities, get_songs, get_albums, get_scrobbles, appears, entity_info, datestreak, entities_by_name }; +const QueryTypeEnum = enum { firstlast, timescale, entities, get_songs, get_albums, get_scrobbles, appears, entity_info, datestreak, entities_by_name, get_ratings }; const GeneratedQuery = struct { entity: EntityType, @@ -66,6 +68,8 @@ const UnifiedResult = struct { artist_id: ?i64 = null, scrobbles: ?i64 = null, date: ?[]const u8 = null, + score: ?i16 = null, + review: ?[]const u8 = null, }; const EntityInfoResult = struct { @@ -435,6 +439,15 @@ pub fn loadQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQuery { , else => unreachable, }, + .get_ratings => switch (entity) { + .song => + \\SELECT rating AS score, rating_text AS review, TO_CHAR(date, 'YYYY-MM-DD') AS date + \\FROM songratings + \\WHERE song = $1 + \\ORDER BY date DESC; + , + else => unreachable, + }, }, }; } diff --git a/src/types.zig b/src/types.zig index 5f3e0e3..0a66ae7 100644 --- a/src/types.zig +++ b/src/types.zig @@ -129,6 +129,8 @@ pub const TableRow = struct { artistlist: ?[]HyperlinkData = null, scrobbles: ?i64 = null, date: ?[]const u8 = null, + score: ?i16 = null, + review: ?[]const u8 = null, }; pub const HyperlinkData = struct {