From 7ecdb1c0dd37156be8ac11d32f7e85b7a7800215 Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Tue, 22 Mar 2022 10:46:38 +0000 Subject: [PATCH] API sorting improvements: - Add endpoints for getting/updating sorting methods - Results from library and title endpoints are now sorted --- src/library/library.cr | 13 ++++-- src/library/title.cr | 11 ++++- src/library/types.cr | 7 +++ src/routes/api.cr | 96 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 116 insertions(+), 11 deletions(-) diff --git a/src/library/library.cr b/src/library/library.cr index 210912f..f55df03 100644 --- a/src/library/library.cr +++ b/src/library/library.cr @@ -139,14 +139,21 @@ class Library titles.flat_map &.deep_entries end - def build_json(*, slim = false, depth = -1) + def build_json(*, slim = false, depth = -1, sort_context = nil) JSON.build do |json| json.object do json.field "dir", @dir json.field "titles" do json.array do - self.titles.each do |title| - json.raw title.build_json(slim: slim, depth: depth) + _titles = if sort_context + sorted_titles sort_context[:username], + sort_context[:opt] + else + self.titles + end + _titles.each do |title| + json.raw title.build_json(slim: slim, depth: depth, + sort_context: sort_context) end end end diff --git a/src/library/title.cr b/src/library/title.cr index bc84434..49ce8af 100644 --- a/src/library/title.cr +++ b/src/library/title.cr @@ -218,9 +218,16 @@ class Title unless depth == 0 json.field "titles" do json.array do - self.titles.each do |title| + _titles = if sort_context + sorted_titles sort_context[:username], + sort_context[:opt] + else + self.titles + end + _titles.each do |title| json.raw title.build_json(slim: slim, - depth: depth > 0 ? depth - 1 : depth) + depth: depth > 0 ? depth - 1 : depth, + sort_context: sort_context) end end end diff --git a/src/library/types.cr b/src/library/types.cr index 4c9dc93..973aa5e 100644 --- a/src/library/types.cr +++ b/src/library/types.cr @@ -55,6 +55,13 @@ class SortOptions def to_tuple {@method.to_s.underscore, ascend} end + + def to_json + { + "method" => method.to_s.underscore, + "ascend" => ascend, + }.to_json + end end struct Image diff --git a/src/routes/api.cr b/src/routes/api.cr index 5f33234..0154a2b 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -167,6 +167,7 @@ struct APIRouter end Koa.describe "Returns the book with title `tid`", <<-MD + The entries and titles will be sorted by the default sorting method for the logged-in user. - Supply the `slim` query parameter to strip away "display_name", "cover_url", and "mtime" from the returned object to speed up the loading time - Supply the `depth` query parameter to control the depth of nested titles to return. - When `depth` is 1, returns the top-level titles and sub-titles/entries one level in them @@ -177,8 +178,6 @@ struct APIRouter Koa.path "tid", desc: "Title ID" Koa.query "slim" Koa.query "depth" - Koa.query "sort", desc: "Sorting option for entries. Can be one of 'auto', 'title', 'progress', 'time_added' and 'time_modified'" - Koa.query "ascend", desc: "Sorting direction for entries. Set to 0 for the descending order. Doesn't work without specifying 'sort'" Koa.response 200, schema: "title" Koa.response 404, "Title not found" Koa.tag "library" @@ -186,13 +185,12 @@ struct APIRouter begin username = get_username env - sort_opt = SortOptions.new - get_sort_opt - tid = env.params.url["tid"] title = Library.default.get_title tid raise "Title ID `#{tid}` not found" if title.nil? + sort_opt = SortOptions.from_info_json title.dir, username + slim = !env.params.query["slim"]?.nil? depth = env.params.query["depth"]?.try(&.to_i?) || -1 @@ -206,7 +204,81 @@ struct APIRouter end end + Koa.describe "Returns the sorting option of a title or the library", <<-MD + - If the query parameter `tid` is supplied, returns the sorting option of the title identified by the `tid`. + - If the query parameter `tid` is missing, returns the sorting option of the library. + MD + Koa.query "tid" + Koa.response 200, schema: { + "method" => String?, + "ascend" => Bool?, + "error" => String?, + } + Koa.tag "library" + get "/api/sort_opt" do |env| + username = get_username env + + tid = env.params.query["tid"]? + dir = if tid + (Library.default.get_title tid).not_nil!.dir + else + Library.default.dir + end + sort_opt = SortOptions.from_info_json dir, username + send_json env, sort_opt.to_json + rescue e + Logger.error e + send_json env, { + "success" => false, + "error" => e.message, + }.to_json + end + + Koa.describe "Updates the sorting option of a title or the library", <<-MD + - When the `tid` field is supplied in the body, updates the sorting option of the title identified by the `tid`. + - When the `tid` field is missing in the body, updates the sorting option of the library. + MD + Koa.body schema: { + "tid" => String?, + "method" => String, + "ascend" => Bool, + } + Koa.response 200, schema: { + "success" => Bool, + "error" => String?, + } + Koa.tag "library" + put "/api/sort_opt" do |env| + username = get_username env + + tid = env.params.json["tid"]?.try &.as String + dir = if tid + (Library.default.get_title tid).not_nil!.dir + else + Library.default.dir + end + + method = env.params.json["sort"].as String + ascend = env.params.json["ascend"].as Bool + sort_opt = SortOptions.new method, ascend + + TitleInfo.new dir do |info| + info.sort_by[username] = sort_opt.to_tuple + info.save + end + send_json env, { + "success" => true, + }.to_json + rescue e + Logger.error e + send_json env, { + "success" => false, + "error" => e.message, + }.to_json + end + Koa.describe "Returns the entire library with all titles and entries", <<-MD + The titles will be sorted by the default sorting method for the logged-in user. - Supply the `slim` query parameter to strip away "display_name", "cover_url", and "mtime" from the returned object to speed up the loading time - Supply the `dpeth` query parameter to control the depth of nested titles to return. - When `depth` is 1, returns the requested title and sub-titles/entries one level in it @@ -222,10 +294,22 @@ struct APIRouter } Koa.tag "library" get "/api/library" do |env| + username = get_username env + + sort_opt = SortOptions.from_info_json Library.default.dir, username + slim = !env.params.query["slim"]?.nil? depth = env.params.query["depth"]?.try(&.to_i?) || -1 - send_json env, Library.default.build_json(slim: slim, depth: depth) + send_json env, Library.default.build_json(slim: slim, depth: depth, + sort_context: {username: username, + opt: sort_opt}) + rescue e + Logger.error e + send_json env, { + "success" => false, + "error" => e.message, + }.to_json end Koa.describe "Triggers a library scan"