mirror of https://github.com/kiwix/libkiwix.git
/catalog/v2/entries going through OPDSDumper
OPDSDumper sensed threats to its job security, so it lobbied to be involved in handling the /catalog/v2 endpoints, too.
This commit is contained in:
parent
dfad1c3815
commit
cdacc0caf1
|
@ -51,11 +51,26 @@ class OPDSDumper
|
|||
/**
|
||||
* Dump the OPDS feed.
|
||||
*
|
||||
* @param id The id of the library.
|
||||
* @param bookIds the ids of the books to include in the feed
|
||||
* @return The OPDS feed.
|
||||
*/
|
||||
std::string dumpOPDSFeed(const std::vector<std::string>& bookIds);
|
||||
|
||||
/**
|
||||
* Dump the OPDS feed.
|
||||
*
|
||||
* @param bookIds the ids of the books to include in the feed
|
||||
* @return The OPDS feed.
|
||||
*/
|
||||
std::string dumpOPDSFeedV2(const std::vector<std::string>& bookIds, const std::string& query) const;
|
||||
|
||||
/**
|
||||
* Set the id of the library.
|
||||
*
|
||||
* @param id the id to use.
|
||||
*/
|
||||
void setLibraryId(const std::string& id) { this->libraryId = id;}
|
||||
|
||||
/**
|
||||
* Set the id of the opds stream.
|
||||
*
|
||||
|
@ -103,6 +118,7 @@ class OPDSDumper
|
|||
protected:
|
||||
kiwix::Library* library;
|
||||
std::string id;
|
||||
std::string libraryId;
|
||||
std::string title;
|
||||
std::string date;
|
||||
std::string rootLocation;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <vector>
|
||||
#include <map>
|
||||
#include <zim/zim.h>
|
||||
#include <mustache.hpp>
|
||||
|
||||
namespace pugi {
|
||||
class xml_node;
|
||||
|
@ -47,6 +48,9 @@ namespace kiwix
|
|||
MimeCounterType parseMimetypeCounter(const std::string& counterData);
|
||||
|
||||
std::string gen_date_str();
|
||||
std::string gen_uuid(const std::string& s);
|
||||
|
||||
std::string render_template(const std::string& template_str, kainjow::mustache::data data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
|
||||
#include "tools/otherTools.h"
|
||||
|
||||
#include "kiwixlib-resources.h"
|
||||
#include <mustache.hpp>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
/* Constructor */
|
||||
|
@ -135,4 +138,45 @@ string OPDSDumper::dumpOPDSFeed(const std::vector<std::string>& bookIds)
|
|||
return nodeToString(root_node);
|
||||
}
|
||||
|
||||
typedef kainjow::mustache::data MustacheData;
|
||||
|
||||
string OPDSDumper::dumpOPDSFeedV2(const std::vector<std::string>& bookIds, const std::string& query) const
|
||||
{
|
||||
kainjow::mustache::list bookData;
|
||||
for ( const auto& bookId : bookIds ) {
|
||||
const Book& book = library->getBookById(bookId);
|
||||
const MustacheData bookUrl = book.getUrl().empty()
|
||||
? MustacheData(false)
|
||||
: MustacheData(book.getUrl());
|
||||
bookData.push_back(kainjow::mustache::object{
|
||||
{"id", "urn:uuid:"+book.getId()},
|
||||
{"name", book.getName()},
|
||||
{"title", book.getTitle()},
|
||||
{"description", book.getDescription()},
|
||||
{"language", book.getLanguage()},
|
||||
{"content_id", book.getHumanReadableIdFromPath()},
|
||||
{"updated", book.getDate() + "T00:00:00Z"},
|
||||
{"category", book.getCategory()},
|
||||
{"flavour", book.getFlavour()},
|
||||
{"tags", book.getTags()},
|
||||
{"article_count", to_string(book.getArticleCount())},
|
||||
{"media_count", to_string(book.getMediaCount())},
|
||||
{"author_name", book.getCreator()},
|
||||
{"publisher_name", book.getPublisher()},
|
||||
{"url", bookUrl},
|
||||
{"size", to_string(book.getSize())},
|
||||
});
|
||||
}
|
||||
|
||||
const kainjow::mustache::object template_data{
|
||||
{"date", gen_date_str()},
|
||||
{"endpoint_root", rootLocation + "/catalog/v2"},
|
||||
{"feed_id", gen_uuid(libraryId + "/entries?"+query)},
|
||||
{"filter", query.empty() ? MustacheData(false) : MustacheData(query)},
|
||||
{"books", bookData }
|
||||
};
|
||||
|
||||
return render_template(RESOURCE::catalog_v2_entries_xml, template_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -79,11 +79,6 @@ namespace kiwix {
|
|||
namespace
|
||||
{
|
||||
|
||||
inline std::string gen_uuid(const std::string& s)
|
||||
{
|
||||
return to_string(zim::Uuid::generate(s));
|
||||
}
|
||||
|
||||
inline std::string normalizeRootUrl(const std::string& rootUrl)
|
||||
{
|
||||
return (rootUrl.empty() || rootUrl[0] == '/')
|
||||
|
@ -767,53 +762,17 @@ std::unique_ptr<Response> InternalServer::handle_catalog_v2_root(const RequestCo
|
|||
|
||||
std::unique_ptr<Response> InternalServer::handle_catalog_v2_entries(const RequestContext& request)
|
||||
{
|
||||
const std::string root_url = normalizeRootUrl(m_root);
|
||||
|
||||
const auto now = gen_date_str();
|
||||
kainjow::mustache::list bookData;
|
||||
const auto filter = get_search_filter(request);
|
||||
const auto allMatchingEntries = mp_library->filter(filter);
|
||||
const size_t count = request.get_optional_param("count", 10UL);
|
||||
const size_t start = request.get_optional_param("start", 0UL);
|
||||
for ( const auto& bookId : subrange(allMatchingEntries, start, count) ) {
|
||||
const Book& book = mp_library->getBookById(bookId);
|
||||
const MustacheData bookUrl = book.getUrl().empty()
|
||||
? MustacheData(false)
|
||||
: MustacheData(book.getUrl());
|
||||
bookData.push_back(kainjow::mustache::object{
|
||||
{"id", "urn:uuid:"+book.getId()},
|
||||
{"name", book.getName()},
|
||||
{"title", book.getTitle()},
|
||||
{"description", book.getDescription()},
|
||||
{"language", book.getLanguage()},
|
||||
{"content_id", book.getHumanReadableIdFromPath()},
|
||||
{"updated", book.getDate() + "T00:00:00Z"},
|
||||
{"category", book.getCategory()},
|
||||
{"flavour", book.getFlavour()},
|
||||
{"tags", book.getTags()},
|
||||
{"article_count", to_string(book.getArticleCount())},
|
||||
{"media_count", to_string(book.getMediaCount())},
|
||||
{"author_name", book.getCreator()},
|
||||
{"publisher_name", book.getPublisher()},
|
||||
{"url", bookUrl},
|
||||
{"size", to_string(book.getSize())},
|
||||
});
|
||||
}
|
||||
|
||||
const auto query = request.get_query().empty()
|
||||
? MustacheData(false)
|
||||
: MustacheData(request.get_query());
|
||||
|
||||
const auto bookIds = subrange(mp_library->filter(filter), start, count);
|
||||
OPDSDumper opdsDumper(mp_library);
|
||||
opdsDumper.setRootLocation(normalizeRootUrl(m_root));
|
||||
opdsDumper.setLibraryId(m_library_id);
|
||||
const auto opdsFeed = opdsDumper.dumpOPDSFeedV2(bookIds, request.get_query());
|
||||
return ContentResponse::build(
|
||||
*this,
|
||||
RESOURCE::catalog_v2_entries_xml,
|
||||
kainjow::mustache::object{
|
||||
{"date", now},
|
||||
{"endpoint_root", root_url + "/catalog/v2"},
|
||||
{"feed_id", gen_uuid(m_library_id + "/entries?"+request.get_query())},
|
||||
{"filter", query},
|
||||
{"books", bookData }
|
||||
},
|
||||
opdsFeed,
|
||||
"application/atom+xml;profile=opds-catalog;kind=acquisition"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "tools/regexTools.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include "tools/otherTools.h"
|
||||
|
||||
#include "string.h"
|
||||
#include <mustache.hpp>
|
||||
|
@ -38,17 +39,6 @@ namespace
|
|||
{
|
||||
// some utilities
|
||||
|
||||
std::string render_template(const std::string& template_str, kainjow::mustache::data data)
|
||||
{
|
||||
kainjow::mustache::mustache tmpl(template_str);
|
||||
kainjow::mustache::data urlencode{kainjow::mustache::lambda2{
|
||||
[](const std::string& str,const kainjow::mustache::renderer& r) { return urlEncode(r(str), true); }}};
|
||||
data.set("urlencoded", urlencode);
|
||||
std::stringstream ss;
|
||||
tmpl.render(data, [&ss](const std::string& str) { ss << str; });
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string get_mime_type(const zim::Item& item)
|
||||
{
|
||||
try {
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <sstream>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include <zim/uuid.h>
|
||||
|
||||
|
||||
static std::map<std::string, std::string> codeisomapping {
|
||||
{ "aa", "aar" },
|
||||
|
@ -358,3 +360,19 @@ std::string kiwix::gen_date_str()
|
|||
<< std::setw(2) << std::setfill('0') << tm->tm_sec << "Z";
|
||||
return is.str();
|
||||
}
|
||||
|
||||
std::string kiwix::gen_uuid(const std::string& s)
|
||||
{
|
||||
return kiwix::to_string(zim::Uuid::generate(s));
|
||||
}
|
||||
|
||||
std::string kiwix::render_template(const std::string& template_str, kainjow::mustache::data data)
|
||||
{
|
||||
kainjow::mustache::mustache tmpl(template_str);
|
||||
kainjow::mustache::data urlencode{kainjow::mustache::lambda2{
|
||||
[](const std::string& str,const kainjow::mustache::renderer& r) { return urlEncode(r(str), true); }}};
|
||||
data.set("urlencoded", urlencode);
|
||||
std::stringstream ss;
|
||||
tmpl.render(data, [&ss](const std::string& str) { ss << str; });
|
||||
return ss.str();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue