Make the Library`s book vector private.

Move a lot of methods from Manager to Library. Because books is private
and thoses methods are better in Library.
This commit is contained in:
Matthieu Gautier 2018-08-30 10:53:27 +02:00
parent 741c67786a
commit c9eac04050
4 changed files with 301 additions and 438 deletions

View File

@ -38,6 +38,7 @@ namespace kiwix
{ {
enum supportedIndexType { UNKNOWN, XAPIAN }; enum supportedIndexType { UNKNOWN, XAPIAN };
class OPDSDumper;
/** /**
* A class to store information about a book (a zim file) * A class to store information about a book (a zim file)
@ -88,6 +89,7 @@ class Book
*/ */
class Library class Library
{ {
std::vector<kiwix::Book> books;
public: public:
Library(); Library();
~Library(); ~Library();
@ -105,26 +107,72 @@ class Library
*/ */
bool addBook(const Book& book); bool addBook(const Book& book);
Book& getBookById(const std::string& id);
bool removeBookByIndex(const unsigned int bookIndex);
/** /**
* Remove a book from the library. * Remove a book from the library.
* *
* @param bookIndex the index of the book to remove. * @param id the id of the book to remove.
* @return True * @return True if the book were in the lirbrary and has been removed.
*/ */
bool removeBookByIndex(const unsigned int bookIndex); bool removeBookById(const std::string& id);
vector<kiwix::Book> books;
/* /**
* 'current' is the variable storing the current content/book id * Write the library to a file.
* in the library. This is used to be able to load per default a *
* content. As Kiwix may work with many library XML files, you may * @param path the path of the file to write to.
* have "current" defined many time with different values. The * @return True if the library has been correctly save.
* last XML file read has the priority, Although we do not have an
* library object for each file, we want to be able to fallback to
* an 'old' current book if the one which should be load
* failed. That is the reason why we need a stack here
*/ */
bool writeToFile(const std::string& path);
/**
* Get the number of book in the library.
*
* @param localBooks If we must count local books (books with a path).
* @param remoteBooks If we must count remote books (books with an url)
* @return The number of books.
*/
unsigned int getBookCount(const bool localBooks, const bool remoteBooks);
/**
* Filter the library and generate a new one with the keep elements.
*
* @param search List only books with search in the title or description.
* @return A `Library`.
*/
Library filter(const string& search);
/**
* Get all langagues of the books in the library.
*
* @return A list of languages.
*/
std::vector<std::string> getBooksLanguages();
/**
* Get all book creators of the books in the library.
*
* @return A list of book creators.
*/
std::vector<std::string> getBooksCreators();
/**
* Get all book publishers of the books in the library.
*
* @return A list of book publishers.
*/
std::vector<std::string> getBooksPublishers();
/**
* Get all book ids of the books in the library.
*
* @return A list of book ids.
*/
std::vector<std::string> getBooksIds();
stack<string> current; stack<string> current;
friend class OPDSDumper;
}; };
} }

View File

@ -99,15 +99,6 @@ class Manager
*/ */
bool readOpds(const string& content, const std::string& urlHost); bool readOpds(const string& content, const std::string& urlHost);
/**
* Write the library to a file.
*
* @param path the path of the file to write.
* @return True.
*/
bool writeFile(const string path);
/** /**
* Remove a book from the library. * Remove a book from the library.
* *
@ -193,13 +184,6 @@ class Manager
const string url = "", const string url = "",
const bool checkMetaData = false); const bool checkMetaData = false);
/**
* Clone and return the internal library.
*
* @return A clone of the library.
*/
Library cloneLibrary();
/** /**
* Get the book corresponding to an id. * Get the book corresponding to an id.
* *
@ -217,15 +201,6 @@ class Manager
*/ */
bool getCurrentBook(Book& book); bool getCurrentBook(Book& book);
/**
* Get the number of book in the library.
*
* @param localBooks If we must count local books (books with a path).
* @param remoteBooks If we must count remote books (books with an url)
* @return The number of books.
*/
unsigned int getBookCount(const bool localBooks, const bool remoteBooks);
/** /**
* Update the "last open date" of a book * Update the "last open date" of a book
* *
@ -266,43 +241,6 @@ class Manager
const string publisher, const string publisher,
const string search); const string search);
/**
* Filter the library and generate a new one with the keep elements.
*
* @param search List only books with search in the title or description.
* @return A `Library`.
*/
Library filter(const string& search);
/**
* Get all langagues of the books in the library.
*
* @return A list of languages.
*/
vector<string> getBooksLanguages();
/**
* Get all book creators of the books in the library.
*
* @return A list of book creators.
*/
vector<string> getBooksCreators();
/**
* Get all book publishers of the books in the library.
*
* @return A list of book publishers.
*/
vector<string> getBooksPublishers();
/**
* Get all book ids of the books in the library.
*
* @return A list of book ids.
*/
vector<string> getBooksIds();
string writableLibraryPath; string writableLibraryPath;
vector<std::string> bookIdList; vector<std::string> bookIdList;

View File

@ -19,6 +19,8 @@
#include "library.h" #include "library.h"
#include <pugixml.hpp>
namespace kiwix namespace kiwix
{ {
/* Constructor */ /* Constructor */
@ -136,6 +138,8 @@ Library::Library() : version(KIWIX_LIBRARY_VERSION)
Library::~Library() Library::~Library()
{ {
} }
bool Library::addBook(const Book& book) bool Library::addBook(const Book& book)
{ {
/* Try to find it */ /* Try to find it */
@ -152,9 +156,219 @@ bool Library::addBook(const Book& book)
return true; return true;
} }
bool Library::removeBookByIndex(const unsigned int bookIndex) bool Library::removeBookByIndex(const unsigned int bookIndex)
{ {
books.erase(books.begin() + bookIndex); books.erase(books.begin() + bookIndex);
return true; return true;
} }
bool Library::removeBookById(const std::string& id)
{
auto itr = books.begin();
for(; itr != books.end(); itr ++) {
if (itr->id == id) {
break;
}
}
if (itr != books.end()) {
books.erase(itr);
return true;
}
return false;
}
Book& Library::getBookById(const std::string& id)
{
for(auto& book: books) {
if(book.id == id) {
return book;
}
}
throw std::runtime_error("");
}
unsigned int Library::getBookCount(const bool localBooks,
const bool remoteBooks)
{
unsigned int result = 0;
for (auto& book: books) {
if ((!book.path.empty() && localBooks)
|| (book.path.empty() && remoteBooks)) {
result++;
}
}
return result;
}
Library Library::filter(const std::string& search) {
Library library;
if (search.empty()) {
return library;
}
for(auto& book:books) {
if (matchRegex(book.title, "\\Q" + search + "\\E")
|| matchRegex(book.description, "\\Q" + search + "\\E")) {
library.addBook(book);
}
}
return library;
}
bool Library::writeToFile(const std::string& path) {
pugi::xml_document doc;
/* Add the library node */
pugi::xml_node libraryNode = doc.append_child("library");
if (!version.empty())
libraryNode.append_attribute("version") = version.c_str();
/* Add each book */
for (auto& book: books) {
if (!book.readOnly) {
pugi::xml_node bookNode = libraryNode.append_child("book");
bookNode.append_attribute("id") = book.id.c_str();
if (!book.path.empty()) {
bookNode.append_attribute("path") = book.path.c_str();
}
if (!book.last.empty() && book.last != "undefined") {
bookNode.append_attribute("last") = book.last.c_str();
}
if (!book.indexPath.empty())
bookNode.append_attribute("indexPath") = book.indexPath.c_str();
if (!book.indexPath.empty() || !book.indexPathAbsolute.empty()) {
if (book.indexType == XAPIAN) {
bookNode.append_attribute("indexType") = "xapian";
}
}
if (book.origId.empty()) {
if (!book.title.empty())
bookNode.append_attribute("title") = book.title.c_str();
if (!book.name.empty())
bookNode.append_attribute("name") = book.name.c_str();
if (!book.tags.empty())
bookNode.append_attribute("tags") = book.tags.c_str();
if (!book.description.empty())
bookNode.append_attribute("description") = book.description.c_str();
if (!book.language.empty())
bookNode.append_attribute("language") = book.language.c_str();
if (!book.creator.empty())
bookNode.append_attribute("creator") = book.creator.c_str();
if (!book.publisher.empty())
bookNode.append_attribute("publisher") = book.publisher.c_str();
if (!book.favicon.empty())
bookNode.append_attribute("favicon") = book.favicon.c_str();
if (!book.faviconMimeType.empty())
bookNode.append_attribute("faviconMimeType")
= book.faviconMimeType.c_str();
}
if (!book.date.empty()) {
bookNode.append_attribute("date") = book.date.c_str();
}
if (!book.url.empty()) {
bookNode.append_attribute("url") = book.url.c_str();
}
if (!book.origId.empty())
bookNode.append_attribute("origId") = book.origId.c_str();
if (!book.articleCount.empty())
bookNode.append_attribute("articleCount") = book.articleCount.c_str();
if (!book.mediaCount.empty())
bookNode.append_attribute("mediaCount") = book.mediaCount.c_str();
if (!book.size.empty()) {
bookNode.append_attribute("size") = book.size.c_str();
}
}
}
/* saving file */
return doc.save_file(path.c_str());
}
std::vector<std::string> Library::getBooksLanguages()
{
std::vector<std::string> booksLanguages;
std::map<std::string, bool> booksLanguagesMap;
for (auto& book: books) {
if (booksLanguagesMap.find(book.language) == booksLanguagesMap.end()) {
if (book.origId.empty()) {
booksLanguagesMap[book.language] = true;
booksLanguages.push_back(book.language);
}
}
}
return booksLanguages;
}
std::vector<std::string> Library::getBooksCreators()
{
std::vector<std::string> booksCreators;
std::map<std::string, bool> booksCreatorsMap;
for (auto& book: books) {
if (booksCreatorsMap.find(book.creator) == booksCreatorsMap.end()) {
if (book.origId.empty()) {
booksCreatorsMap[book.creator] = true;
booksCreators.push_back(book.creator);
}
}
}
return booksCreators;
}
std::vector<std::string> Library::getBooksIds()
{
std::vector<std::string> booksIds;
for (auto& book: books) {
booksIds.push_back(book.id);
}
return booksIds;
}
std::vector<std::string> Library::getBooksPublishers()
{
std::vector<std::string> booksPublishers;
std::map<std::string, bool> booksPublishersMap;
for (auto& book:books) {
if (booksPublishersMap.find(book.publisher) == booksPublishersMap.end()) {
if (book.origId.empty()) {
booksPublishersMap[book.publisher] = true;
booksPublishers.push_back(book.publisher);
}
}
}
return booksPublishers;
}
} }

View File

@ -194,105 +194,6 @@ bool Manager::readFile(const string nativePath,
return retVal; return retVal;
} }
bool Manager::writeFile(const string path)
{
pugi::xml_document doc;
/* Add the library node */
pugi::xml_node libraryNode = doc.append_child("library");
if (!getCurrentBookId().empty()) {
libraryNode.append_attribute("current") = getCurrentBookId().c_str();
}
if (!library.version.empty())
libraryNode.append_attribute("version") = library.version.c_str();
/* Add each book */
std::vector<kiwix::Book>::iterator itr;
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (!itr->readOnly) {
this->checkAndCleanBookPaths(*itr, path);
pugi::xml_node bookNode = libraryNode.append_child("book");
bookNode.append_attribute("id") = itr->id.c_str();
if (!itr->path.empty()) {
bookNode.append_attribute("path") = itr->path.c_str();
}
if (!itr->last.empty() && itr->last != "undefined") {
bookNode.append_attribute("last") = itr->last.c_str();
}
if (!itr->indexPath.empty())
bookNode.append_attribute("indexPath") = itr->indexPath.c_str();
if (!itr->indexPath.empty() || !itr->indexPathAbsolute.empty()) {
if (itr->indexType == XAPIAN) {
bookNode.append_attribute("indexType") = "xapian";
}
}
if (itr->origId.empty()) {
if (!itr->title.empty())
bookNode.append_attribute("title") = itr->title.c_str();
if (!itr->name.empty())
bookNode.append_attribute("name") = itr->name.c_str();
if (!itr->tags.empty())
bookNode.append_attribute("tags") = itr->tags.c_str();
if (!itr->description.empty())
bookNode.append_attribute("description") = itr->description.c_str();
if (!itr->language.empty())
bookNode.append_attribute("language") = itr->language.c_str();
if (!itr->creator.empty())
bookNode.append_attribute("creator") = itr->creator.c_str();
if (!itr->publisher.empty())
bookNode.append_attribute("publisher") = itr->publisher.c_str();
if (!itr->favicon.empty())
bookNode.append_attribute("favicon") = itr->favicon.c_str();
if (!itr->faviconMimeType.empty())
bookNode.append_attribute("faviconMimeType")
= itr->faviconMimeType.c_str();
}
if (!itr->date.empty()) {
bookNode.append_attribute("date") = itr->date.c_str();
}
if (!itr->url.empty()) {
bookNode.append_attribute("url") = itr->url.c_str();
}
if (!itr->origId.empty())
bookNode.append_attribute("origId") = itr->origId.c_str();
if (!itr->articleCount.empty())
bookNode.append_attribute("articleCount") = itr->articleCount.c_str();
if (!itr->mediaCount.empty())
bookNode.append_attribute("mediaCount") = itr->mediaCount.c_str();
if (!itr->size.empty()) {
bookNode.append_attribute("size") = itr->size.c_str();
}
}
}
/* saving file */
doc.save_file(path.c_str());
return true;
}
bool Manager::setCurrentBookId(const string id) bool Manager::setCurrentBookId(const string id)
{ {
@ -411,300 +312,62 @@ bool Manager::removeBookByIndex(const unsigned int bookIndex)
bool Manager::removeBookById(const string id) bool Manager::removeBookById(const string id)
{ {
unsigned int bookIndex = 0; return library.removeBookById(id);
std::vector<kiwix::Book>::iterator itr;
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (itr->id == id) {
return this->library.removeBookByIndex(bookIndex);
}
bookIndex++;
}
return false;
} }
vector<string> Manager::getBooksLanguages()
{
std::vector<string> booksLanguages;
std::vector<kiwix::Book>::iterator itr;
std::map<string, bool> booksLanguagesMap;
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortByLanguage);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (booksLanguagesMap.find(itr->language) == booksLanguagesMap.end()) {
if (itr->origId.empty()) {
booksLanguagesMap[itr->language] = true;
booksLanguages.push_back(itr->language);
}
}
}
return booksLanguages;
}
vector<string> Manager::getBooksCreators()
{
std::vector<string> booksCreators;
std::vector<kiwix::Book>::iterator itr;
std::map<string, bool> booksCreatorsMap;
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortByCreator);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (booksCreatorsMap.find(itr->creator) == booksCreatorsMap.end()) {
if (itr->origId.empty()) {
booksCreatorsMap[itr->creator] = true;
booksCreators.push_back(itr->creator);
}
}
}
return booksCreators;
}
vector<string> Manager::getBooksIds()
{
std::vector<string> booksIds;
std::vector<kiwix::Book>::iterator itr;
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
booksIds.push_back(itr->id);
}
return booksIds;
}
vector<string> Manager::getBooksPublishers()
{
std::vector<string> booksPublishers;
std::vector<kiwix::Book>::iterator itr;
std::map<string, bool> booksPublishersMap;
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortByPublisher);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (booksPublishersMap.find(itr->publisher) == booksPublishersMap.end()) {
if (itr->origId.empty()) {
booksPublishersMap[itr->publisher] = true;
booksPublishers.push_back(itr->publisher);
}
}
}
return booksPublishers;
}
kiwix::Library Manager::cloneLibrary()
{
return this->library;
}
bool Manager::getCurrentBook(Book& book) bool Manager::getCurrentBook(Book& book)
{ {
string currentBookId = getCurrentBookId(); string currentBookId = getCurrentBookId();
if (currentBookId.empty()) { if (currentBookId.empty()) {
return false; return false;
} else { } else {
getBookById(currentBookId, book); book = library.getBookById(currentBookId);
return true; return true;
} }
} }
bool Manager::getBookById(const string id, Book& book)
{
std::vector<kiwix::Book>::iterator itr;
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (itr->id == id) {
book = *itr;
return true;
}
}
return false;
}
bool Manager::updateBookLastOpenDateById(const string id) bool Manager::updateBookLastOpenDateById(const string id)
{ try {
std::vector<kiwix::Book>::iterator itr; auto book = library.getBookById(id);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (itr->id == id) {
char unixdate[12]; char unixdate[12];
sprintf(unixdate, "%d", (int)time(NULL)); sprintf(unixdate, "%d", (int)time(NULL));
itr->last = unixdate; book.last = unixdate;
return true; return true;
} } catch(...) {
}
return false; return false;
} }
bool Manager::setBookIndex(const string id, bool Manager::setBookIndex(const string id,
const string path, const string path,
const supportedIndexType type) const supportedIndexType type)
{ try {
std::vector<kiwix::Book>::iterator itr; auto book = library.getBookById(id);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) { book.indexPath = path;
if (itr->id == id) { book.indexPathAbsolute = isRelativePath(path)
itr->indexPath = path;
itr->indexPathAbsolute
= isRelativePath(path)
? computeAbsolutePath( ? computeAbsolutePath(
removeLastPathElement(writableLibraryPath, true, false), removeLastPathElement(writableLibraryPath, true, false),
path) path)
: path; : path;
itr->indexType = type; book.indexType = type;
return true; return true;
} } catch (...) {
}
return false; return false;
} }
bool Manager::setBookPath(const string id, const string path) bool Manager::setBookPath(const string id, const string path)
{ try {
std::vector<kiwix::Book>::iterator itr; auto book = library.getBookById(id);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) { book.path = path;
if (itr->id == id) { book.pathAbsolute = isRelativePath(path)
itr->path = path;
itr->pathAbsolute
= isRelativePath(path)
? computeAbsolutePath( ? computeAbsolutePath(
removeLastPathElement(writableLibraryPath, true, false), removeLastPathElement(writableLibraryPath, true, false),
path) path)
: path; : path;
return true; return true;
} } catch(...) {
}
return false; return false;
} }
void Manager::removeBookPaths()
{
std::vector<kiwix::Book>::iterator itr;
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
itr->path = "";
itr->pathAbsolute = "";
}
}
unsigned int Manager::getBookCount(const bool localBooks,
const bool remoteBooks)
{
unsigned int result = 0;
std::vector<kiwix::Book>::iterator itr;
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if ((!itr->path.empty() && localBooks)
|| (itr->path.empty() && remoteBooks)) {
result++;
}
}
return result;
}
bool Manager::listBooks(const supportedListMode mode,
const supportedListSortBy sortBy,
const unsigned int maxSize,
const string language,
const string creator,
const string publisher,
const string search)
{
this->bookIdList.clear();
std::vector<kiwix::Book>::iterator itr;
/* Sort */
if (sortBy == TITLE) {
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortByTitle);
} else if (sortBy == SIZE) {
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortBySize);
} else if (sortBy == DATE) {
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortByDate);
} else if (sortBy == CREATOR) {
std::sort(
library.books.begin(), library.books.end(), kiwix::Book::sortByCreator);
} else if (sortBy == PUBLISHER) {
std::sort(library.books.begin(),
library.books.end(),
kiwix::Book::sortByPublisher);
}
/* Special sort for LASTOPEN */
if (mode == LASTOPEN) {
std::sort(library.books.begin(),
library.books.end(),
kiwix::Book::sortByLastOpen);
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
if (!itr->last.empty()) {
this->bookIdList.push_back(itr->id);
}
}
} else {
/* Generate the list of book id */
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
bool ok = true;
if (mode == LOCAL && itr->path.empty()) {
ok = false;
}
if (ok == true && mode == REMOTE
&& (!itr->path.empty() || itr->url.empty())) {
ok = false;
}
if (ok == true && maxSize != 0
&& (unsigned int)atoi(itr->size.c_str()) > maxSize * 1024 * 1024) {
ok = false;
}
if (ok == true && !language.empty()
&& !matchRegex(itr->language, language)) {
ok = false;
}
if (ok == true && !creator.empty() && itr->creator != creator) {
ok = false;
}
if (ok == true && !publisher.empty() && itr->publisher != publisher) {
ok = false;
}
if ((ok == true && !search.empty())
&& !(matchRegex(itr->title, "\\Q" + search + "\\E")
|| matchRegex(itr->description, "\\Q" + search + "\\E")
|| matchRegex(itr->language, "\\Q" + search + "\\E"))) {
ok = false;
}
if (ok == true) {
this->bookIdList.push_back(itr->id);
}
}
}
return true;
}
Library Manager::filter(const std::string& search) {
Library library;
if (search.empty()) {
return library;
}
for(auto book:this->library.books) {
if (matchRegex(book.title, "\\Q" + search + "\\E")
|| matchRegex(book.description, "\\Q" + search + "\\E")) {
library.addBook(book);
}
}
return library;
}
void Manager::checkAndCleanBookPaths(Book& book, const string& libraryPath) void Manager::checkAndCleanBookPaths(Book& book, const string& libraryPath)
{ {