Merge pull request #841 from kiwix/catalog_filtering_by_multiple_languages

This commit is contained in:
Matthieu Gautier 2022-11-01 19:23:36 +01:00 committed by GitHub
commit bf9aeffbfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 7 deletions

View File

@ -106,7 +106,15 @@ class Filter {
Filter& rejectTags(const Tags& tags); Filter& rejectTags(const Tags& tags);
Filter& category(std::string category); Filter& category(std::string category);
/**
* Set the filter to only accept books in the specified language.
*
* Multiple languages can be specified as a comma-separated list (in
* which case a book in any of those languages will match).
*/
Filter& lang(std::string lang); Filter& lang(std::string lang);
Filter& publisher(std::string publisher); Filter& publisher(std::string publisher);
Filter& creator(std::string creator); Filter& creator(std::string creator);
Filter& maxSize(size_t size); Filter& maxSize(size_t size);

View File

@ -535,9 +535,20 @@ Xapian::Query categoryQuery(const std::string& category)
return Xapian::Query("XC" + normalizeText(category)); return Xapian::Query("XC" + normalizeText(category));
} }
Xapian::Query langQuery(const std::string& lang) Xapian::Query langQuery(const std::string& commaSeparatedLanguageList)
{ {
return Xapian::Query("L" + normalizeText(lang)); Xapian::Query q;
bool firstIteration = true;
for ( const auto& lang : kiwix::split(commaSeparatedLanguageList, ",") ) {
const Xapian::Query singleLangQuery("L" + normalizeText(lang));
if ( firstIteration ) {
q = singleLangQuery;
firstIteration = false;
} else {
q = Xapian::Query(Xapian::Query::OP_OR, q, singleLangQuery);
}
}
return q;
} }
Xapian::Query publisherQuery(const std::string& publisher) Xapian::Query publisherQuery(const std::string& publisher)

View File

@ -1036,9 +1036,6 @@ InternalServer::search_catalog(const RequestContext& request,
kiwix::OPDSDumper& opdsDumper) kiwix::OPDSDumper& opdsDumper)
{ {
const auto filter = get_search_filter(request); const auto filter = get_search_filter(request);
const std::string q = filter.hasQuery()
? filter.getQuery()
: "<Empty query>";
std::vector<std::string> bookIdsToDump = mp_library->filter(filter); std::vector<std::string> bookIdsToDump = mp_library->filter(filter);
const auto totalResults = bookIdsToDump.size(); const auto totalResults = bookIdsToDump.size();
const size_t count = request.get_optional_param("count", 10UL); const size_t count = request.get_optional_param("count", 10UL);

View File

@ -114,7 +114,7 @@ std::string maskVariableOPDSFeedData(std::string s)
"569344" \ "569344" \
) )
#define CHARLES_RAY_CATALOG_ENTRY _CHARLES_RAY_CATALOG_ENTRY("zimfile%26other") #define CHARLES_RAY_CATALOG_ENTRY _CHARLES_RAY_CATALOG_ENTRY("zimfile%26other")
#define CHARLES_RAY_CATALOG_ENTRY_NO_MAPPER _CHARLES_RAY_CATALOG_ENTRY("charlesray") #define CHARLES_RAY_CATALOG_ENTRY_NO_MAPPER _CHARLES_RAY_CATALOG_ENTRY("charlesray")
#define _RAY_CHARLES_CATALOG_ENTRY(CONTENT_NAME) CATALOG_ENTRY(\ #define _RAY_CHARLES_CATALOG_ENTRY(CONTENT_NAME) CATALOG_ENTRY(\
@ -133,7 +133,7 @@ std::string maskVariableOPDSFeedData(std::string s)
"569344"\ "569344"\
) )
#define RAY_CHARLES_CATALOG_ENTRY _RAY_CHARLES_CATALOG_ENTRY("zimfile") #define RAY_CHARLES_CATALOG_ENTRY _RAY_CHARLES_CATALOG_ENTRY("zimfile")
#define RAY_CHARLES_CATALOG_ENTRY_NO_MAPPER _RAY_CHARLES_CATALOG_ENTRY("raycharles") #define RAY_CHARLES_CATALOG_ENTRY_NO_MAPPER _RAY_CHARLES_CATALOG_ENTRY("raycharles")
#define UNCATEGORIZED_RAY_CHARLES_CATALOG_ENTRY CATALOG_ENTRY(\ #define UNCATEGORIZED_RAY_CHARLES_CATALOG_ENTRY CATALOG_ENTRY(\
@ -317,6 +317,44 @@ TEST_F(LibraryServerTest, catalog_search_by_category)
); );
} }
TEST_F(LibraryServerTest, catalog_search_by_language)
{
{
const auto r = zfs1_->GET("/ROOT/catalog/search?lang=eng");
EXPECT_EQ(r->status, 200);
EXPECT_EQ(maskVariableOPDSFeedData(r->body),
OPDS_FEED_TAG
" <id>12345678-90ab-cdef-1234-567890abcdef</id>\n"
" <title>Filtered zims (lang=eng)</title>\n"
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n"
" <totalResults>1</totalResults>\n"
" <startIndex>0</startIndex>\n"
" <itemsPerPage>1</itemsPerPage>\n"
CATALOG_LINK_TAGS
RAY_CHARLES_CATALOG_ENTRY
"</feed>\n"
);
}
{
const auto r = zfs1_->GET("/ROOT/catalog/search?lang=eng,fra");
EXPECT_EQ(r->status, 200);
EXPECT_EQ(maskVariableOPDSFeedData(r->body),
OPDS_FEED_TAG
" <id>12345678-90ab-cdef-1234-567890abcdef</id>\n"
" <title>Filtered zims (lang=eng,fra)</title>\n"
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n"
" <totalResults>2</totalResults>\n"
" <startIndex>0</startIndex>\n"
" <itemsPerPage>2</itemsPerPage>\n"
CATALOG_LINK_TAGS
RAY_CHARLES_CATALOG_ENTRY
CHARLES_RAY_CATALOG_ENTRY
"</feed>\n"
);
}
}
TEST_F(LibraryServerTest, catalog_search_results_pagination) TEST_F(LibraryServerTest, catalog_search_results_pagination)
{ {
{ {
@ -667,6 +705,40 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_search_terms)
); );
} }
TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_language)
{
{
const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?lang=eng");
EXPECT_EQ(r->status, 200);
EXPECT_EQ(maskVariableOPDSFeedData(r->body),
CATALOG_V2_ENTRIES_PREAMBLE("?lang=eng")
" <title>Filtered Entries (lang=eng)</title>\n"
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n"
" <totalResults>1</totalResults>\n"
" <startIndex>0</startIndex>\n"
" <itemsPerPage>1</itemsPerPage>\n"
RAY_CHARLES_CATALOG_ENTRY
"</feed>\n"
);
}
{
const auto r = zfs1_->GET("/ROOT/catalog/v2/entries?lang=eng,fra");
EXPECT_EQ(r->status, 200);
EXPECT_EQ(maskVariableOPDSFeedData(r->body),
CATALOG_V2_ENTRIES_PREAMBLE("?lang=eng,fra")
" <title>Filtered Entries (lang=eng,fra)</title>\n"
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n"
" <totalResults>2</totalResults>\n"
" <startIndex>0</startIndex>\n"
" <itemsPerPage>2</itemsPerPage>\n"
RAY_CHARLES_CATALOG_ENTRY
CHARLES_RAY_CATALOG_ENTRY
"</feed>\n"
);
}
}
TEST_F(LibraryServerTest, catalog_v2_individual_entry_access) TEST_F(LibraryServerTest, catalog_v2_individual_entry_access)
{ {
const auto r = zfs1_->GET("/ROOT/catalog/v2/entry/raycharles"); const auto r = zfs1_->GET("/ROOT/catalog/v2/entry/raycharles");