diff --git a/src/database.cpp b/src/database.cpp index de1b2b3..ac3abe5 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -548,6 +548,33 @@ namespace Database { work.commit(); } + /* + * Executes the prepared statement INSERT_FREELANCER_TEMPLATE + * Takes an open pqxx::connection and the strings name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, freelancerEmail + * returns errorLevel + * 0 = no error + * 1 = query error + * 2 = critical error + */ + int executePreparedStatement_INSERT_FREELANCER_TEMPLATE(pqxx::connection &connection, const std::string& name, const std::string& content, const std::string& contactdata, const std::string& contactinformation, const std::string& currencypreference, const std::string& priceupfront, const std::string& priceondeliver, const std::string& freelancerEmail) { + try { + pqxx::work work(connection); + work.exec_prepared(PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE, name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, freelancerEmail); + work.commit(); + } + catch (pqxx::sql_error const &e) { + std::cerr + << "Database error: " << e.what() << std::endl + << "Query was: " << e.query() << std::endl; + return 1; + } + catch (std::exception const &e) { + std::cerr << e.what() << std::endl; + return 2; + } + return 0; + } + /* * Prepares a statement based on ID * Takes an open pqxx::connection, the statement id diff --git a/src/databaseStatementConstCollection.cpp b/src/databaseStatementConstCollection.cpp index 747319d..4053847 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -186,6 +186,13 @@ namespace DatabaseStatementConstCollection { const static std::string PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT = "updateExpirationLoginLockOut"; const static std::string SQL_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT = "update loginlockout set (attempts, expiration) = (0, CURRENT_TIMESTAMP + make_interval(secs => $2)) where email = $1;"; + /* + * Name and Statement for prepared statement to try to add a new template to a freelancer + * $1-8 -> name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, emailaddress + */ + const static std::string PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE = "insertFreelancerTemplate"; + const static std::string SQL_STATEMENT_INSERT_FREELANCER_TEMPLATE = "INSERT INTO templates(freelancerid, name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver) VALUES((select freelancers.id from freelancers where emailaddress = $8), $1, $2, $3, $4, $5, $6, $7);"; + /* * IDs of prepared statements */ @@ -218,6 +225,7 @@ namespace DatabaseStatementConstCollection { const static int ID_INSERT_LOGIN_LOCK_OUT = 26; const static int ID_SELECT_CHECK_LOGIN_LOCK_OUT_ATTEMPTS = 27; const static int ID_UPDATE_EXPIRATION_LOGIN_LOCK_OUT = 28; + const static int ID_INSERT_FREELANCER_TEMPLATE = 29; /* * Easy access to prepared statements via prepared statement name @@ -251,7 +259,8 @@ namespace DatabaseStatementConstCollection { {PREPARED_STATEMENT_UPDATE_INCREMENT_LOGIN_LOCK_OUT_ATTEMPTS, SQL_STATEMENT_UPDATE_INCREMENT_LOGIN_LOCK_OUT_ATTEMPTS}, {PREPARED_STATEMENT_INSERT_LOGIN_LOCK_OUT, SQL_STATEMENT_INSERT_LOGIN_LOCK_OUT}, {PREPARED_STATEMENT_SELECT_CHECK_LOGIN_LOCK_OUT_ATTEMPTS, SQL_STATEMENT_SELECT_CHECK_LOGIN_LOCK_OUT_ATTEMPTS}, - {PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT, SQL_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT} + {PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT, SQL_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT}, + {PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE, SQL_STATEMENT_INSERT_FREELANCER_TEMPLATE} }; /* * Easy access to prepared statement name via int @@ -285,7 +294,8 @@ namespace DatabaseStatementConstCollection { {ID_UPDATE_INCREMENT_LOGIN_LOCK_OUT_ATTEMPTS, PREPARED_STATEMENT_UPDATE_INCREMENT_LOGIN_LOCK_OUT_ATTEMPTS}, {ID_INSERT_LOGIN_LOCK_OUT, PREPARED_STATEMENT_INSERT_LOGIN_LOCK_OUT}, {ID_SELECT_CHECK_LOGIN_LOCK_OUT_ATTEMPTS, PREPARED_STATEMENT_SELECT_CHECK_LOGIN_LOCK_OUT_ATTEMPTS}, - {ID_UPDATE_EXPIRATION_LOGIN_LOCK_OUT, PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT} + {ID_UPDATE_EXPIRATION_LOGIN_LOCK_OUT, PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT}, + {ID_INSERT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE} }; /* diff --git a/src/main.cpp b/src/main.cpp index 83a49a1..a5a1f21 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include @@ -144,7 +143,7 @@ int main(int argc, char *argv[]) { if (!resultTemplate.empty()) { //use freelancerID based on SQL_STATEMENT_SELECT_TEMPLATE pqxx::result resultCommissionState = Database::executePreparedStatement_SELECT_FREELANCER_COMMISSION_STATE(databaseConnection, stoi(resultTemplate.at(0).at(2).c_str())); - //the commissionstate + //the commission-state if (resultCommissionState.empty() || stoi(resultCommissionState.at(0).at(0).c_str()) == 1) commissionState = true; } @@ -230,7 +229,7 @@ int main(int argc, char *argv[]) { pqxx::result resultCommissionState = Database::executePreparedStatement_SELECT_FREELANCER_COMMISSION_STATE(databaseConnection, newRequest.freelancerID); - //the commissionstate + //the commission-state if (resultCommissionState.empty() || stoi(resultCommissionState.at(0).at(0).c_str()) == 1) { ctx[MUSTACHE_ERROR_COMMISSIONS_CLOSED] = true; } @@ -639,7 +638,7 @@ int main(int argc, char *argv[]) { }); /* - * Page for freelancer to create/delete/edit Templates + * Page for freelancer to create/select Templates */ CROW_ROUTE(app, "/freelancer/templateManagement") ([&, configuration](const crow::request& getRequest ) { @@ -655,7 +654,81 @@ int main(int argc, char *argv[]) { }); /* - * Page for freelancer to create/delete/edit Templates + * Page for freelancer to create new Template + */ + CROW_ROUTE(app, "/freelancer/templateManagement/template/new") + ([&, configuration](const crow::request& getRequest ) { + auto& cookieCtx = app.get_context(getRequest); + crow::mustache::context ctx; + if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { + ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; + } + auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_CREATE_NEW); + return page.render(ctx); + }); + + /* + * Page for freelancer to create new Template fulfilment + */ + CROW_ROUTE(app, "/freelancer/templateManagement/template/new/fulfilment").methods("POST"_method) + ([&, configuration](const crow::request& postRequest ) { + auto& cookieCtx = app.get_context(postRequest); + crow::mustache::context ctx; + if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { + ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; + string name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver; + + string postRequestBody = postRequest.body; + Utilities::decodeString(postRequestBody); + vector splitPostRequestBody = Utilities::splitStringIntoVector(postRequestBody, '&'); + + for (const string& item : splitPostRequestBody) { + vector splitItem = Utilities::splitStringIntoVector(item, '='); + if (splitItem.at(0) == "templatename") + name = splitItem.at(1); + if (splitItem.at(0) == "templatecontent") + content = splitItem.at(1); + if (splitItem.at(0) == "templatecontactdata") + contactdata = splitItem.at(1); + if (splitItem.at(0) == "templatecontactinformation") + contactinformation = splitItem.at(1); + if (splitItem.at(0) == "templatecurrencypreference") + currencypreference = splitItem.at(1); + if (splitItem.at(0) == "templatepriceupfront") + priceupfront = splitItem.at(1); + if (splitItem.at(0) == "templatepriceondeliver") + priceondeliver = splitItem.at(1); + } + + if (!Utilities::checkIfStrIsNumber(priceupfront)) + priceupfront = "0"; + if (!Utilities::checkIfStrIsNumber(priceondeliver)) + priceondeliver = "0"; + + + pqxx::connection databaseConnection(configuration.databaseConnectionString); + Database::prepareStatement(databaseConnection, ID_INSERT_FREELANCER_TEMPLATE); + int errorLevel = Database::executePreparedStatement_INSERT_FREELANCER_TEMPLATE( + databaseConnection, name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL)); + if (errorLevel == 0) { + ctx["templatename"] = name; + ctx["contactdata"] = contactdata; + ctx["contactinformation"] = contactinformation; + ctx["currencypreference"] = currencypreference; + ctx["priceupfront"] = priceupfront; + ctx["priceondeliver"] = priceondeliver; + ctx["content"] = content; + } + else { + ctx[MUSTACHE_FREELANCER_TEMPLATE_CREATION_ERROR] = true; + } + } + auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_CREATE_NEW_FULFILMENT); + return page.render(ctx); + }); + + /* + * Page for freelancer to view/delete/edit a Template */ CROW_ROUTE(app, "/freelancer/templateManagement/template/").methods("POST"_method) ([&, configuration](const crow::request& postRequest, string templateName ) { @@ -695,7 +768,23 @@ int main(int argc, char *argv[]) { return page.render(ctx); }); - + /* + * Execute Template Operation + * todo:implement + */ + CROW_ROUTE(app, "/freelancer/templateManagement/fulfilment").methods("POST"_method) + ([&, configuration](const crow::request& postRequest ) { + auto& cookieCtx = app.get_context(postRequest); + cout << postRequest.body << endl; + crow::mustache::context ctx; + if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { + ctx = Utilities::getFreelancerTemplates(configuration, cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL)); + ctx["freelanceremail"] = cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL); + ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; + } + auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT); + return page.render(ctx); + }); diff --git a/src/templateConstCollection.cpp b/src/templateConstCollection.cpp index a456c99..ff6c3d1 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -26,6 +26,8 @@ namespace TemplateConstCollection { const static std::string TEMPLATE_FREELANCER_PROFILE = "freelancer_Profile.html"; const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT = "freelancer_Template_Management.html"; const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_FULFILMENT = "freelancer_Template_Management_Fulfilment.html"; + const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_CREATE_NEW = "freelancer_Template_Management_Create_New.html"; + const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_CREATE_NEW_FULFILMENT = "freelancer_Template_Management_Create_New_Fulfilment.html"; //Mustache Error/Success variable names const static std::string MUSTACHE_ERROR_COMMISSIONS_CLOSED = "ERROR_COMMISSIONS_CLOSED"; @@ -54,6 +56,7 @@ namespace TemplateConstCollection { const static std::string MUSTACHE_RESET_SUCCESS = "RESET_SUCCESS"; const static std::string MUSTACHE_LOGIN_SUCCESS = "LOGIN_SUCCESS"; const static std::string MUSTACHE_FREELANCER_TEMPLATE_OPERATION_ERROR_NO_TEMPLATE = "TEMPLATE_OPERATION_ERROR_NO_TEMPLATE"; + const static std::string MUSTACHE_FREELANCER_TEMPLATE_CREATION_ERROR = "TEMPLATE_CREATION_ERROR"; //Mustache Cookie variable names const static std::string MUSTACHE_COOKIE_LOGGED_IN = "COOKIE_LOGGED_IN"; diff --git a/src/utilities.cpp b/src/utilities.cpp index 14d39ac..eb536b4 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -522,5 +522,18 @@ namespace Utilities { } return resultJsonFreelancerTemplate; } + + /* + * Checks if a given string is a valid number + */ + bool checkIfStrIsNumber(const std::string& numberString) { + try { + std::stod(numberString); + } + catch (const std::invalid_argument& ia) { + return false; + } + return true; + } } #endif \ No newline at end of file diff --git a/templates/freelancer_Template_Management_Create_New.html b/templates/freelancer_Template_Management_Create_New.html new file mode 100644 index 0000000..4d2d9fb --- /dev/null +++ b/templates/freelancer_Template_Management_Create_New.html @@ -0,0 +1,38 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{^COOKIE_LOGGED_IN}} + Please Log in. + {{/COOKIE_LOGGED_IN}} + {{#COOKIE_LOGGED_IN}} +
+
+
+
+
+
+
+
+
+ +
+
+ {{/COOKIE_LOGGED_IN}} +
+
+ +
+
+ +
+
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file diff --git a/templates/freelancer_Template_Management_Create_New_Fulfilment.html b/templates/freelancer_Template_Management_Create_New_Fulfilment.html new file mode 100644 index 0000000..c9af617 --- /dev/null +++ b/templates/freelancer_Template_Management_Create_New_Fulfilment.html @@ -0,0 +1,50 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{^COOKIE_LOGGED_IN}} + Please Log in. + {{/COOKIE_LOGGED_IN}} + {{#COOKIE_LOGGED_IN}} + {{^TEMPLATE_CREATION_ERROR}} +

Template Successfully Created

+

Template: {{templatename}}

+
Contact Information:
+
+ {{contactdata}}
+ {{contactinformation}} +
+
+
Payment Information:
+
+ Prefered Currency: {{currencypreference}}
+ Price: Upfront: {{priceupfront}} - On Delivery: {{priceondeliver}}
+
+
+
Description:
+
{{content}}
+ {{/TEMPLATE_CREATION_ERROR}} + {{#TEMPLATE_CREATION_ERROR}} + Unable to create Template +
+ +
+ {{/TEMPLATE_CREATION_ERROR}} + {{/COOKIE_LOGGED_IN}} +
+
+ +
+
+ +
+
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file