diff --git a/src/database.cpp b/src/database.cpp index f269684..dacfc0e 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -195,6 +195,30 @@ namespace Database { return result; } + /* + * Executes the SELECT_FREELANCERS_WITHCOMMISSIONSSTATE statement + * Takes an open pqxx::connection + */ + pqxx::result executeStatement_SELECT_FREELANCERS_COUNT(pqxx::connection &connection) { + pqxx::work work(connection); + pqxx::result result = work.exec(SQL_Statement_SELECT_FREELANCERS_COUNT); + work.commit(); + return result; + } + + /* + * Executes the SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET statement + * Takes an open pqxx::connection the limit and the offset + */ + pqxx::result executePreparedStatement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET(pqxx::connection &connection, int limit, int offset) { + if (offset < 0) + offset = 0; + pqxx::work work(connection); + pqxx::result result = work.exec_prepared(PREPARED_STATEMENT_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET, limit, offset); + work.commit(); + return result; + } + /* * Executes the PURGE_EXPIRED_FREELANCER_RESET_KEYS statement * Takes an open pqxx::connection diff --git a/src/databaseStatementConstCollection.cpp b/src/databaseStatementConstCollection.cpp index b016d86..13075cc 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -144,6 +144,12 @@ namespace DatabaseStatementConstCollection { const static std::string PREPARED_STATEMENT_DELETE_FREELANCER_RESET_KEY = "deleteFreelancerResetKey"; const static std::string SQL_STATEMENT_DELETE_FREELANCER_RESET_KEY = "delete from passwordresetkeys where freelanceremail = $1;"; + /* + * Name and Statement for prepared statement to delete specific reset key of a freelancer + */ + const static std::string PREPARED_STATEMENT_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET = "selectFreelancersWithCommissionstateLimitedAndOffset"; + const static std::string SQL_STATEMENT_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET = "select id, name, basicInformation , (case when (commissionlimit <= (select count(*) as requestCount from requests where requests.accepted = true and requests.completed = false and requests.freelancerid = freelancers.id group by freelancers.id)) then 'Closed' else 'Open' end) as commissionsclosed from freelancers order by name limit $1 offset $2;"; + /* * IDs of prepared statements */ @@ -169,6 +175,7 @@ namespace DatabaseStatementConstCollection { const static int ID_SELECT_CHECK_FREELANCER_RESET_KEY_EXPIRED = 19; const static int ID_INSERT_FREELANCER_RESET_KEY = 20; const static int ID_DELETE_FREELANCER_RESET_KEY = 21; + const static int ID_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET = 22; /* * Easy access to prepared statements via prepared statement name @@ -195,7 +202,8 @@ namespace DatabaseStatementConstCollection { {PREPARED_STATEMENT_SELECT_FREELANCER_EMAIL_FROM_PASSWORD_RESET_KEY, SQL_STATEMENT_SELECT_FREELANCER_EMAIL_FROM_PASSWORD_RESET_KEY}, {PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_RESET_KEY_EXPIRED, SQL_STATEMENT_SELECT_CHECK_FREELANCER_RESET_KEY_EXPIRED}, {PREPARED_STATEMENT_INSERT_FREELANCER_RESET_KEY, SQL_STATEMENT_INSERT_FREELANCER_RESET_KEY}, - {PREPARED_STATEMENT_DELETE_FREELANCER_RESET_KEY, SQL_STATEMENT_DELETE_FREELANCER_RESET_KEY} + {PREPARED_STATEMENT_DELETE_FREELANCER_RESET_KEY, SQL_STATEMENT_DELETE_FREELANCER_RESET_KEY}, + {PREPARED_STATEMENT_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET, SQL_STATEMENT_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET} }; /* * Easy access to prepared statement name via int @@ -222,7 +230,8 @@ namespace DatabaseStatementConstCollection { {ID_SELECT_FREELANCER_EMAIL_FROM_PASSWORD_RESET_KEY, PREPARED_STATEMENT_SELECT_FREELANCER_EMAIL_FROM_PASSWORD_RESET_KEY}, {ID_SELECT_CHECK_FREELANCER_RESET_KEY_EXPIRED, PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_RESET_KEY_EXPIRED}, {ID_INSERT_FREELANCER_RESET_KEY, PREPARED_STATEMENT_INSERT_FREELANCER_RESET_KEY}, - {ID_DELETE_FREELANCER_RESET_KEY, PREPARED_STATEMENT_DELETE_FREELANCER_RESET_KEY} + {ID_DELETE_FREELANCER_RESET_KEY, PREPARED_STATEMENT_DELETE_FREELANCER_RESET_KEY}, + {ID_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET, PREPARED_STATEMENT_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET} }; /* @@ -235,5 +244,11 @@ namespace DatabaseStatementConstCollection { * Delivers if the commission limit has been reached and if the commissions are closed based on the accepted/completed state of the freelancers requests */ const static std::string SQL_Statement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE = "select id, name, basicInformation , (case when (commissionlimit <= (select count(*) as requestCount from requests where requests.accepted = true and requests.completed = false and requests.freelancerid = freelancers.id group by freelancers.id)) then 'Closed' else 'Open' end) as commissionsclosed from freelancers order by name;"; + + /* + * Selects freelancer count + */ + const static std::string SQL_Statement_SELECT_FREELANCERS_COUNT = "select count(*) from freelancers;"; + } #endif \ No newline at end of file diff --git a/src/default-cavecomm.conf b/src/default-cavecomm.conf index 4ad6aba..ae45f48 100644 --- a/src/default-cavecomm.conf +++ b/src/default-cavecomm.conf @@ -15,6 +15,7 @@ # regularTaskExecution={false} # regularTaskExecutionIntervalSeconds={900} 15min # regularTaskExecutionModules={} # options separated by "|": reeeprint|counter +# itemsPerPage{0} #0 == no pagination @@ -41,6 +42,8 @@ regularTaskExecution=true; regularTaskExecutionIntervalSeconds=2; -regularTaskExecutionModules=reeeprint|counter; +regularTaskExecutionModules=; + +itemsPerPage=5; #configend# diff --git a/src/main.cpp b/src/main.cpp index ba19567..7b2f069 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -36,9 +37,28 @@ int main(int argc, char *argv[]) { * Freelancer Profile listing for customers */ CROW_ROUTE(app, "/").methods("POST"_method, "GET"_method) - ([configuration]() { + ([configuration](const crow::request& request) { + int selectedPage = 1; + if (!request.url_params.keys().empty()) { + string selectedPageString = request.url_params.get("page"); + if (!selectedPageString.empty()) + selectedPage = stoi(selectedPageString); + } auto page = crow::mustache::load(TEMPLATE_CUSTOMER_INDEX_FREELANCER_LISTING); - crow::mustache::context ctx(Utilities::getFreelancerListing(configuration)); + crow::mustache::context ctx(Utilities::getFreelancerListing(configuration, selectedPage)); + if (configuration.itemsPerPage > 0) { + ctx[MUSTACHE_PAGINATION] = true; + vector pages = Utilities::getFreelancerIndexPagination(configuration); + ctx[MUSTACHE_PAGINATION_NUMBERS] = pages; + if (selectedPage <= 1) + ctx[MUSTACHE_PAGINATION_PREVIOUS] = 1; + else + ctx[MUSTACHE_PAGINATION_PREVIOUS] = selectedPage - 1; + if (selectedPage >= pages.size()) + ctx[MUSTACHE_PAGINATION_NEXT] = pages.size(); + else + ctx[MUSTACHE_PAGINATION_NEXT] = selectedPage + 1; + } return page.render(ctx); }); diff --git a/src/templateConstCollection.cpp b/src/templateConstCollection.cpp index fa48b18..14fb3b3 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -52,5 +52,11 @@ namespace TemplateConstCollection { //Mustache Cookie variable names const static std::string MUSTACHE_COOKIE_LOGGED_IN = "COOKIE_LOGGED_IN"; + + //Mustache variable names + const static std::string MUSTACHE_PAGINATION = "PAGINATION"; + const static std::string MUSTACHE_PAGINATION_NUMBERS = "PAGINATION_NUMBERS"; + const static std::string MUSTACHE_PAGINATION_PREVIOUS = "PAGINATION_PREVIOUS"; + const static std::string MUSTACHE_PAGINATION_NEXT = "PAGINATION_NEXT"; } #endif \ No newline at end of file diff --git a/src/utilities.cpp b/src/utilities.cpp index bd35133..8b04c76 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -78,6 +79,7 @@ namespace Utilities { {MODULE_NAME_REEE_PRINT, false}, {MODULE_NAME_COUNTER_PRINT, false} }; + int itemsPerPage = 20; /* * validates existence of mandatory variables in config @@ -142,57 +144,64 @@ namespace Utilities { if (lineVector.size() == 2) { std::cout << lineVector.at(0) << " - " << lineVector.at(1) << std::endl; + std::string lineString = trimFromDelimiter(lineVector.at(1), ';'); + if (lineString.empty()) + continue; if (lineVector.at(0) == "emailAddress") { - emailAddress = trimFromDelimiter(lineVector.at(1), ';'); + emailAddress = lineString; continue; } if (lineVector.at(0) == "emailPassword") { - emailPassword = trimFromDelimiter(lineVector.at(1), ';'); + emailPassword = lineString; continue; } if (lineVector.at(0) == "emailServerAddress") { - emailServerAddress = trimFromDelimiter(lineVector.at(1), ';'); + emailServerAddress = lineString; continue; } if (lineVector.at(0) == "emailServerPort") { - emailServerPort = std::stoi(trimFromDelimiter(lineVector.at(1), ';')); + emailServerPort = std::stoi(lineString); continue; } if (lineVector.at(0) == "emailAddressDisplay") { - emailAddressDisplay = trimFromDelimiter(lineVector.at(1), ';'); + emailAddressDisplay = lineString; continue; } if (lineVector.at(0) == "databaseConnectionString") { - databaseConnectionString = trimFromDelimiter(lineVector.at(1), ';'); + databaseConnectionString = lineString; continue; } if (lineVector.at(0) == "sslCrtPath") { - sslCrtPath = trimFromDelimiter(lineVector.at(1), ';'); + sslCrtPath = lineString; continue; } if (lineVector.at(0) == "sslKeyPath") { - sslKeyPath = trimFromDelimiter(lineVector.at(1), ';'); + sslKeyPath = lineString; continue; } if (lineVector.at(0) == "domain") { - domain = trimFromDelimiter(lineVector.at(1), ';'); + domain = lineString; continue; } if (lineVector.at(0) == "regularTaskExecution") { - regularTaskExecution = (trimFromDelimiter(lineVector.at(1), ';') == "true"); + regularTaskExecution = (lineString == "true"); continue; } if (lineVector.at(0) == "regularTaskExecutionIntervalSeconds") { - regularTaskExecutionIntervalSeconds = std::stoi(trimFromDelimiter(lineVector.at(1), ';')); + regularTaskExecutionIntervalSeconds = std::stoi(lineString); continue; } if (lineVector.at(0) == "regularTaskExecutionModules") { - std::vector modules = Utilities::splitStringIntoVector(trimFromDelimiter(lineVector.at(1), ';'), '|'); + std::vector modules = Utilities::splitStringIntoVector(lineString, '|'); for (const std::string& module : modules) { regularTaskExecutionModules.at(module) = true; } continue; } + if (lineVector.at(0) == "itemsPerPage") { + itemsPerPage = std::stoi(lineString); + continue; + } } } } @@ -356,12 +365,36 @@ namespace Utilities { * takes configuration * returns crow::json::wvalue with the Freelancer profile listing */ - crow::json::wvalue getFreelancerListing(const Utilities::config& configuration) { + crow::json::wvalue getFreelancerListing(const Utilities::config& configuration, int page) { pqxx::connection databaseConnection(configuration.databaseConnectionString); - pqxx::result result = Database::executeStatement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE(databaseConnection); + pqxx::result result; + if (configuration.itemsPerPage == 0) + result = Database::executeStatement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE(databaseConnection); + else { + Database::prepareStatement(databaseConnection, ID_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET); + result = Database::executePreparedStatement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET(databaseConnection, configuration.itemsPerPage, configuration.itemsPerPage * (page - 1)); + } + return Database::convertResultToJSON(result, "freelancerProfiles"); } + /* + * Gets a vector with the appropriate pagination for the configuration.itemsPerPage + * takes configuration + * returns vector + */ + std::vector getFreelancerIndexPagination(const Utilities::config& configuration) { + pqxx::connection databaseConnection(configuration.databaseConnectionString); + pqxx::result freelancerCountResult = Database::executeStatement_SELECT_FREELANCERS_COUNT(databaseConnection); + double freelancerCount = std::stoi(freelancerCountResult.at(0).at(0).c_str()); + int pageCount = ceil(freelancerCount / configuration.itemsPerPage); + std::vector pagination; + for (int i = 1; i <= pageCount; ++i) { + pagination.push_back(i); + } + return pagination; + } + /* * Checks if freelancer is logged in * Takes config, the loginkey and freelancerid taken from the secure cookie diff --git a/templates/customerIndex_FreelancerListing.html b/templates/customerIndex_FreelancerListing.html index 67b74b0..81e423b 100644 --- a/templates/customerIndex_FreelancerListing.html +++ b/templates/customerIndex_FreelancerListing.html @@ -23,6 +23,7 @@ {{/freelancerProfiles}} + {{> templateIncludes/pagination.html.html}} {{> templateIncludes/freelancerLoginSignupProfileLogoutInterface.html.html}} diff --git a/templates/templateIncludes/pagination.html.html b/templates/templateIncludes/pagination.html.html new file mode 100644 index 0000000..cb48322 --- /dev/null +++ b/templates/templateIncludes/pagination.html.html @@ -0,0 +1,11 @@ + {{#PAGINATION}} +
+ « - + » | +
+ {{#PAGINATION_NUMBERS}} + {{.}} + {{/PAGINATION_NUMBERS}} +
+
+ {{/PAGINATION}} \ No newline at end of file