Skip to content

Commit

Permalink
language/category filtering in /nojs endpoint
Browse files Browse the repository at this point in the history
Adds language and category filter in /nojs.
Unlike the main page, the filtering is only done after user submits the form.
  • Loading branch information
juuz0 committed Feb 20, 2023
1 parent 1f64bee commit 9f6b559
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 27 deletions.
2 changes: 2 additions & 0 deletions include/library.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ class Filter {
Filter& maxSize(size_t size);
Filter& query(std::string query, bool partial=true);
Filter& name(std::string name);
Filter& clearLang();
Filter& clearCategory();

bool hasQuery() const;
const std::string& getQuery() const { return _query; }
Expand Down
12 changes: 12 additions & 0 deletions src/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,18 @@ Filter& Filter::name(std::string name)
return *this;
}

Filter& Filter::clearLang()
{
activeFilters &= ~LANG;
return *this;
}

Filter& Filter::clearCategory()
{
activeFilters &= ~CATEGORY;
return *this;
}

#define ACTIVE(X) (activeFilters & (X))
#define FILTER(TAG, TEST) if (ACTIVE(TAG) && !(TEST)) { return false; }
bool Filter::hasQuery() const
Expand Down
91 changes: 65 additions & 26 deletions src/opds_dumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "tools/stringTools.h"
#include "tools/otherTools.h"
#include "tools.h"
#include "tools/regexTools.h"

namespace kiwix
{
Expand Down Expand Up @@ -238,7 +239,14 @@ std::string OPDSDumper::dumpOPDSCompleteEntry(const std::string& bookId) const
+ fullEntryXML(book, rootLocation, contentId);
}

std::string OPDSDumper::categoriesOPDSFeed() const
std::string humanFriendlyTitle(std::string title)
{
std::string humanFriendlyString = replaceRegex(title, "_", " ");
humanFriendlyString[0] = toupper(humanFriendlyString[0]);
return humanFriendlyString;
}

kainjow::mustache::list getCategoryList(kiwix::Library *library, std::string libraryId)
{
const auto now = gen_date_str();
kainjow::mustache::list categoryData;
Expand All @@ -248,19 +256,31 @@ std::string OPDSDumper::categoriesOPDSFeed() const
{"name", category},
{"urlencoded_name", urlencodedCategoryName},
{"updated", now},
{"id", gen_uuid(libraryId + "/categories/" + urlencodedCategoryName)}
{"id", gen_uuid(libraryId + "/categories/" + urlencodedCategoryName)},
{"hf_name", humanFriendlyTitle(category)}
});
}
return categoryData;
}

return render_template(
RESOURCE::templates::catalog_v2_categories_xml,
kainjow::mustache::object{
{"date", now},
{"endpoint_root", rootLocation + "/catalog/v2"},
{"feed_id", gen_uuid(libraryId + "/categories")},
{"categories", categoryData }
}
);
kainjow::mustache::list getLanguageList(kiwix::Library *library, std::string libraryId)
{
const auto now = gen_date_str();
kainjow::mustache::list languageData;
std::call_once(fillLanguagesFlag, fillLanguagesMap);
for ( const auto& langAndBookCount : library->getBooksLanguagesWithCounts() ) {
const std::string languageCode = langAndBookCount.first;
const int bookCount = langAndBookCount.second;
const auto languageSelfName = getLanguageSelfName(languageCode);
languageData.push_back(kainjow::mustache::object{
{"lang_code", languageCode},
{"lang_self_name", languageSelfName},
{"book_count", to_string(bookCount)},
{"updated", now},
{"id", gen_uuid(libraryId + "/languages/" + languageCode)}
});
}
return languageData;
}

kainjow::mustache::list getTagList(std::string tags)
Expand All @@ -276,6 +296,22 @@ kainjow::mustache::list getTagList(std::string tags)
return finalTagList;
}

std::string OPDSDumper::categoriesOPDSFeed() const
{
const auto now = gen_date_str();
kainjow::mustache::list categoryData = getCategoryList(library, libraryId);

return render_template(
RESOURCE::templates::catalog_v2_categories_xml,
kainjow::mustache::object{
{"date", now},
{"endpoint_root", rootLocation + "/catalog/v2"},
{"feed_id", gen_uuid(libraryId + "/categories")},
{"categories", categoryData }
}
);
}

std::string OPDSDumper::noJSDownloadLinks(const std::string& bookId) const
{
const auto book = library->getBookById(bookId);
Expand All @@ -292,6 +328,20 @@ std::string OPDSDumper::noJSData(kiwix::Filter filter) const
kainjow::mustache::list booksData;
const auto filteredBooks = library->filter(filter);
const auto searchQuery = filter.getQuery();
auto languages = getLanguageList(library, libraryId);
auto categories = getCategoryList(library, libraryId);

for (auto &category : categories) {
if (category.get("name")->string_value() == filter.getCategory()) {
category["selected"] = true;
}
}

for (auto &language : languages) {
if (language.get("lang_code")->string_value() == filter.getLang()) {
language["selected"] = true;
}
}

for ( const auto& bookId : filteredBooks ) {
const auto bookObj = library->getBookById(bookId);
Expand Down Expand Up @@ -319,28 +369,17 @@ std::string OPDSDumper::noJSData(kiwix::Filter filter) const
kainjow::mustache::object{
{"books", booksData },
{"searchQuery", searchQuery},
{"resultsCount", to_string(filteredBooks.size())}
{"resultsCount", to_string(filteredBooks.size())},
{"languages", languages},
{"categories", categories}
}
);
}

std::string OPDSDumper::languagesOPDSFeed() const
{
const auto now = gen_date_str();
kainjow::mustache::list languageData;
std::call_once(fillLanguagesFlag, fillLanguagesMap);
for ( const auto& langAndBookCount : library->getBooksLanguagesWithCounts() ) {
const std::string languageCode = langAndBookCount.first;
const int bookCount = langAndBookCount.second;
const auto languageSelfName = getLanguageSelfName(languageCode);
languageData.push_back(kainjow::mustache::object{
{"lang_code", languageCode},
{"lang_self_name", languageSelfName},
{"book_count", to_string(bookCount)},
{"updated", now},
{"id", gen_uuid(libraryId + "/languages/" + languageCode)}
});
}
kainjow::mustache::list languageData = getLanguageList(library, libraryId);

return render_template(
RESOURCE::templates::catalog_v2_languages_xml,
Expand Down
10 changes: 9 additions & 1 deletion src/server/internalServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,15 @@ std::unique_ptr<Response> InternalServer::handle_no_js(const RequestContext& req

const auto url = request.get_url();
const auto domains = kiwix::split(url, "/", true, false);
const auto filter = get_search_filter(request);
auto filter = get_search_filter(request);
try {
if (request.get_argument("category") == "") {
filter.clearCategory();
}
if (request.get_argument("lang") == "") {
filter.clearLang();
}
} catch (...) {}
OPDSDumper opdsDumper(mp_library, mp_nameMapper);
opdsDumper.setRootLocation(m_root);
opdsDumper.setLibraryId(getLibraryId());
Expand Down
18 changes: 18 additions & 0 deletions static/templates/no_js.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@
</head>
<body>
<div class='kiwixNav'>
<div class="kiwixNav__filters">
<div class="kiwixNav__select">
<select name="lang" id="languageFilter" class='kiwixNav__kiwixFilter filter' form="kiwixSearchForm">
<option value="" selected>All languages</option>
{{#languages}}
<option value="{{lang_code}}" {{#selected}} selected {{/selected}}>{{lang_self_name}}</option>
{{/languages}}
</select>
</div>
<div class="kiwixNav__select">
<select name="category" id="categoryFilter" class='kiwixNav__kiwixFilter filter' form="kiwixSearchForm">
<option value="">All categories</option>
{{#categories}}
<option value="{{name}}" {{#selected}} selected {{/selected}}>{{hf_name}}</option>
{{/categories}}
</select>
</div>
</div>
<form id='kiwixSearchForm' class='kiwixNav__SearchForm' action="{{root}}/nojs">
<input type="text" name="q" placeholder="Search" id="searchFilter" class='kiwixSearch filter' value="{{searchQuery}}">
<input type="submit" class="kiwixButton kiwixButtonHover" value="Search"/>
Expand Down

0 comments on commit 9f6b559

Please sign in to comment.