Merge pull request #607 from kiwix/issue/571

This commit is contained in:
Matthieu Gautier 2021-10-12 17:40:27 +02:00 committed by GitHub
commit 08e3d52957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 125 additions and 15 deletions

View File

@ -146,6 +146,53 @@ cp ninja ../bin
cd .. cd ..
``` ```
Custom Index Page
-----------------
to use custom welcome page mention `customIndexPage` argument in `kiwix::internalServer()` or use `kiwix::server->setCustomIndexTemplate()`.
(note - while using custom html file please mention all external links as absolute path.)
to create a HTML template with custom JS you need to have a look at various OPDS based endpoints as mentioned [here](https://wiki.kiwix.org/wiki/OPDS) to load books.
To use JS provided by kiwix-serve you can use the following template to start with ->
```
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title><-- Custom Tittle --></title>
<script
type="text/javascript"
src="{{root}}/skin/jquery-ui/external/jquery/jquery.js"
></script>
<script
type="text/javascript"
src="{{root}}/skin/jquery-ui/jquery-ui.min.js"
></script>
<script src="{{root}}/skin/isotope.pkgd.min.js" defer></script>
<script src="{{root}}/skin/iso6391To3.js"></script>
<script type="text/javascript" src="{{root}}/skin/index.js" defer></script>
</head>
<body>
</body>
</html>
```
- To get books listed using `index.js` add - `<div class="book__list"></div>` under body tag.
- To get number of books listed add - `<h3 class="kiwixHomeBody__results"></h3>` under body tag.
- To add language select box add - `<select id="languageFilter"></select>` under body tag.
- To add language select box add - `<select id="categoryFilter"></select>` under body tag.
- To add search box for books use following form -
```
<form id='kiwixSearchForm'>
<input type="text" name="q" placeholder="Search" id="searchFilter" class='kiwixSearch filter'>
<input type="submit" class="searchButton" value="Search"/>
</form>
```
If you compile manually Libmicrohttpd, you might need to compile it If you compile manually Libmicrohttpd, you might need to compile it
without GNU TLS, a bug here will empeach further compilation without GNU TLS, a bug here will empeach further compilation
otherwise. otherwise.

View File

@ -55,6 +55,7 @@ namespace kiwix
void setPort(int port) { m_port = port; } void setPort(int port) { m_port = port; }
void setNbThreads(int threads) { m_nbThreads = threads; } void setNbThreads(int threads) { m_nbThreads = threads; }
void setVerbose(bool verbose) { m_verbose = verbose; } void setVerbose(bool verbose) { m_verbose = verbose; }
void setIndexTemplateString(const std::string& indexTemplateString) { m_indexTemplateString = indexTemplateString; }
void setTaskbar(bool withTaskbar, bool withLibraryButton) void setTaskbar(bool withTaskbar, bool withLibraryButton)
{ m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; } { m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; }
void setBlockExternalLinks(bool blockExternalLinks) void setBlockExternalLinks(bool blockExternalLinks)
@ -65,6 +66,7 @@ namespace kiwix
NameMapper* mp_nameMapper; NameMapper* mp_nameMapper;
std::string m_root = ""; std::string m_root = "";
std::string m_addr = ""; std::string m_addr = "";
std::string m_indexTemplateString = "";
int m_port = 80; int m_port = 80;
int m_nbThreads = 1; int m_nbThreads = 1;
bool m_verbose = false; bool m_verbose = false;

View File

@ -167,5 +167,32 @@ std::vector<std::string> split(const std::string& str, const std::string& delims
* @throw std::out_of_range if iso2 code is not known. * @throw std::out_of_range if iso2 code is not known.
*/ */
std::string converta2toa3(const std::string& a2code); std::string converta2toa3(const std::string& a2code);
/** Extracts content from given file.
*
* This function provides content of a file provided it's path.
*
* @param path The absolute path provided in string format.
* @return Content of corresponding file in string format.
*/
std::string getFileContent(const std::string& path);
/** checks if file exists.
*
* This function returns boolean stating if file exists or not.
*
* @param path The absolute path provided in string format.
* @return Boolean representing if file exists or not.
*/
bool fileExists(const std::string& path);
/** provides mimetype from filename.
*
* This function provides mimetype from file-name.
*
* @param filename string containing filename.
* @return mimetype from filename in string format.
*/
std::string getMimeTypeForFile(const std::string& filename);
} }
#endif // KIWIX_TOOLS_H #endif // KIWIX_TOOLS_H

View File

@ -48,7 +48,8 @@ bool Server::start() {
m_verbose, m_verbose,
m_withTaskbar, m_withTaskbar,
m_withLibraryButton, m_withLibraryButton,
m_blockExternalLinks)); m_blockExternalLinks,
m_indexTemplateString));
return mp_server->start(); return mp_server->start();
} }

View File

@ -128,7 +128,8 @@ InternalServer::InternalServer(Library* library,
bool verbose, bool verbose,
bool withTaskbar, bool withTaskbar,
bool withLibraryButton, bool withLibraryButton,
bool blockExternalLinks) : bool blockExternalLinks,
std::string indexTemplateString) :
m_addr(addr), m_addr(addr),
m_port(port), m_port(port),
m_root(normalizeRootUrl(root)), m_root(normalizeRootUrl(root)),
@ -137,6 +138,7 @@ InternalServer::InternalServer(Library* library,
m_withTaskbar(withTaskbar), m_withTaskbar(withTaskbar),
m_withLibraryButton(withLibraryButton), m_withLibraryButton(withLibraryButton),
m_blockExternalLinks(blockExternalLinks), m_blockExternalLinks(blockExternalLinks),
m_indexTemplateString(indexTemplateString.empty() ? RESOURCE::templates::index_html : indexTemplateString),
mp_daemon(nullptr), mp_daemon(nullptr),
mp_library(library), mp_library(library),
mp_nameMapper(nameMapper ? nameMapper : &defaultNameMapper) mp_nameMapper(nameMapper ? nameMapper : &defaultNameMapper)
@ -336,7 +338,7 @@ InternalServer::get_matching_if_none_match_etag(const RequestContext& r) const
std::unique_ptr<Response> InternalServer::build_homepage(const RequestContext& request) std::unique_ptr<Response> InternalServer::build_homepage(const RequestContext& request)
{ {
return ContentResponse::build(*this, RESOURCE::templates::index_html, get_default_data(), "text/html; charset=utf-8", true); return ContentResponse::build(*this, m_indexTemplateString, get_default_data(), "text/html; charset=utf-8", true);
} }
/** /**

View File

@ -54,7 +54,8 @@ class InternalServer {
bool verbose, bool verbose,
bool withTaskbar, bool withTaskbar,
bool withLibraryButton, bool withLibraryButton,
bool blockExternalLinks); bool blockExternalLinks,
std::string indexTemplateString);
virtual ~InternalServer() = default; virtual ~InternalServer() = default;
MHD_Result handlerCallback(struct MHD_Connection* connection, MHD_Result handlerCallback(struct MHD_Connection* connection,
@ -103,6 +104,7 @@ class InternalServer {
bool m_withTaskbar; bool m_withTaskbar;
bool m_withLibraryButton; bool m_withLibraryButton;
bool m_blockExternalLinks; bool m_blockExternalLinks;
std::string m_indexTemplateString;
struct MHD_Daemon* mp_daemon; struct MHD_Daemon* mp_daemon;
Library* mp_library; Library* mp_library;

View File

@ -269,7 +269,7 @@ std::string getFileSizeAsString(const std::string& path)
return convert.str(); return convert.str();
} }
std::string getFileContent(const std::string& path) std::string kiwix::getFileContent(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
auto wpath = Utf8ToWide(path); auto wpath = Utf8ToWide(path);
@ -302,7 +302,7 @@ std::string getFileContent(const std::string& path)
return content; return content;
} }
bool fileExists(const std::string& path) bool kiwix::fileExists(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
return PathFileExistsW(Utf8ToWide(path).c_str()); return PathFileExistsW(Utf8ToWide(path).c_str());
@ -505,7 +505,7 @@ static std::map<std::string, std::string> extMimeTypes = {
}; };
/* Try to get the mimeType from the file extension */ /* Try to get the mimeType from the file extension */
std::string getMimeTypeForFile(const std::string& filename) std::string kiwix::getMimeTypeForFile(const std::string& filename)
{ {
std::string mimeType = "text/plain"; std::string mimeType = "text/plain";
auto pos = filename.find_last_of("."); auto pos = filename.find_last_of(".");

View File

@ -29,13 +29,10 @@ std::wstring Utf8ToWide(const std::string& str);
unsigned int getFileSize(const std::string& path); unsigned int getFileSize(const std::string& path);
std::string getFileSizeAsString(const std::string& path); std::string getFileSizeAsString(const std::string& path);
std::string getFileContent(const std::string& path);
bool fileExists(const std::string& path);
bool makeDirectory(const std::string& path); bool makeDirectory(const std::string& path);
std::string makeTmpDirectory(); std::string makeTmpDirectory();
bool copyFile(const std::string& sourcePath, const std::string& destPath); bool copyFile(const std::string& sourcePath, const std::string& destPath);
bool writeTextFile(const std::string& path, const std::string& content); bool writeTextFile(const std::string& path, const std::string& content);
std::string getMimeTypeForFile(const std::string& filename);
#endif #endif

View File

@ -54,7 +54,7 @@ public: // types
public: // functions public: // functions
ZimFileServer(int serverPort, std::string libraryFilePath); ZimFileServer(int serverPort, std::string libraryFilePath);
ZimFileServer(int serverPort, const FilePathCollection& zimpaths); ZimFileServer(int serverPort, const FilePathCollection& zimpaths, std::string indexTemplateString = "");
~ZimFileServer(); ~ZimFileServer();
Response GET(const char* path, const Headers& headers = Headers()) Response GET(const char* path, const Headers& headers = Headers())
@ -68,7 +68,7 @@ public: // functions
} }
private: private:
void run(int serverPort); void run(int serverPort, std::string indexTemplateString = "");
private: // data private: // data
kiwix::Library library; kiwix::Library library;
@ -88,7 +88,7 @@ ZimFileServer::ZimFileServer(int serverPort, std::string libraryFilePath)
run(serverPort); run(serverPort);
} }
ZimFileServer::ZimFileServer(int serverPort, const FilePathCollection& zimpaths) ZimFileServer::ZimFileServer(int serverPort, const FilePathCollection& zimpaths, std::string indexTemplateString)
: manager(&this->library) : manager(&this->library)
{ {
for ( const auto& zimpath : zimpaths ) { for ( const auto& zimpath : zimpaths ) {
@ -96,10 +96,10 @@ ZimFileServer::ZimFileServer(int serverPort, const FilePathCollection& zimpaths)
throw std::runtime_error("Unable to add the ZIM file '" + zimpath + "'"); throw std::runtime_error("Unable to add the ZIM file '" + zimpath + "'");
} }
run(serverPort); run(serverPort, indexTemplateString);
} }
void ZimFileServer::run(int serverPort) void ZimFileServer::run(int serverPort, std::string indexTemplateString)
{ {
const std::string address = "127.0.0.1"; const std::string address = "127.0.0.1";
nameMapper.reset(new kiwix::HumanReadableNameMapper(library, false)); nameMapper.reset(new kiwix::HumanReadableNameMapper(library, false));
@ -108,6 +108,9 @@ void ZimFileServer::run(int serverPort)
server->setPort(serverPort); server->setPort(serverPort);
server->setNbThreads(2); server->setNbThreads(2);
server->setVerbose(false); server->setVerbose(false);
if (!indexTemplateString.empty()) {
server->setIndexTemplateString(indexTemplateString);
}
if ( !server->start() ) if ( !server->start() )
throw std::runtime_error("ZimFileServer failed to start"); throw std::runtime_error("ZimFileServer failed to start");
@ -211,6 +214,35 @@ ResourceCollection all200Resources()
return concat(resources200Compressible, resources200Uncompressible); return concat(resources200Compressible, resources200Uncompressible);
} }
TEST(indexTemplateStringTest, emptyIndexTemplate) {
const int PORT = 8001;
const ZimFileServer::FilePathCollection ZIMFILES {
"./test/zimfile.zim",
"./test/corner_cases.zim"
};
ZimFileServer zfs(PORT, ZIMFILES, "");
EXPECT_EQ(200, zfs.GET("/")->status);
}
TEST(indexTemplateStringTest, indexTemplateCheck) {
const int PORT = 8001;
const ZimFileServer::FilePathCollection ZIMFILES {
"./test/zimfile.zim",
"./test/corner_cases.zim"
};
ZimFileServer zfs(PORT, ZIMFILES, "<!DOCTYPE html><head>"
"<title>Welcome to kiwix library</title>"
"</head>"
"</html>");
EXPECT_EQ("<!DOCTYPE html><head>"
"<title>Welcome to kiwix library</title>"
"<link type=\"root\" href=\"\">"
"</head>"
"</html>", zfs.GET("/")->body);
}
TEST_F(ServerTest, 200) TEST_F(ServerTest, 200)
{ {
for ( const Resource& res : all200Resources() ) for ( const Resource& res : all200Resources() )