From 09406b0852b24e60ee209d0b9dbc261996ab36b1 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Mon, 15 May 2023 16:28:25 +0200 Subject: [PATCH 1/9] Template for managment of templates + add button for creation of new template --- templates/freelancer_Template_Management.html | 37 ++++++------ ...lancer_Template_Management_Fulfilment.html | 58 ++++++++++++++----- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/templates/freelancer_Template_Management.html b/templates/freelancer_Template_Management.html index 9072398..5b2c530 100644 --- a/templates/freelancer_Template_Management.html +++ b/templates/freelancer_Template_Management.html @@ -8,23 +8,26 @@ Please Log in. {{/COOKIE_LOGGED_IN}} {{#COOKIE_LOGGED_IN}} -

Freelancer: {{freelanceremail}}

-
-
- - {{#templates}} - - - - - {{/templates}} -
{{name}} -
- - - -
-
+

Freelancer: {{freelanceremail}}

+
+
+ + {{#templates}} + + + + + {{/templates}} +
{{name}} +
+ + + +
+
+
+ +
{{/COOKIE_LOGGED_IN}} {{> templateIncludes/freelancerLoginSignupProfileLogoutInterface.html.html}}
diff --git a/templates/freelancer_Template_Management_Fulfilment.html b/templates/freelancer_Template_Management_Fulfilment.html index cb1716c..b39d950 100644 --- a/templates/freelancer_Template_Management_Fulfilment.html +++ b/templates/freelancer_Template_Management_Fulfilment.html @@ -5,21 +5,49 @@

Freelancer: {{freelancername}}

-

Template: {{templatename}}

-
Contact Information:
-
- {{contactdata}}
- {{contactinformation}} -
-
-
Payment Information:
-
- Prefered Currency: {{currencypreference}}
- Price: {{pricetotal}} - Upfront: {{priceupfront}} - On Delivery: {{priceondeliver}}
-
-
-
Description:
-
{{content}}
+ {{^OPERATION_EDIT}} +

Template: {{templatename}}

+
Contact Information:
+
+ {{contactdata}}
+ {{contactinformation}} +
+
+
Payment Information:
+
+ Prefered Currency: {{currencypreference}}
+ Price: {{pricetotal}} - Upfront: {{priceupfront}} - On Delivery: {{priceondeliver}}
+
+
+
Description:
+
{{content}}
+ {{/OPERATION_EDIT}} + {{#OPERATION_EDIT}} +
+
+
+
+
+
+
+
+
+ +
+
+ {{/OPERATION_EDIT}} + {{#OPERATION_DELETE}} +
+
+ +
+
+ {{/OPERATION_DELETE}} + {{#TEMPLATE_OPERATION_ERROR_NO_TEMPLATE}} +
+ Template could not be found +
+ {{/TEMPLATE_OPERATION_ERROR_NO_TEMPLATE}}
From 383db248b7b0c25933e50af93f182dfd8b3f1f93 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Mon, 15 May 2023 17:52:16 +0200 Subject: [PATCH 2/9] Create new Template +minor refactoring --- src/database.cpp | 27 +++++ src/databaseStatementConstCollection.cpp | 14 ++- src/main.cpp | 101 ++++++++++++++++-- src/templateConstCollection.cpp | 3 + src/utilities.cpp | 13 +++ ...lancer_Template_Management_Create_New.html | 38 +++++++ ...late_Management_Create_New_Fulfilment.html | 50 +++++++++ 7 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 templates/freelancer_Template_Management_Create_New.html create mode 100644 templates/freelancer_Template_Management_Create_New_Fulfilment.html 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 From bbf526f99febd4b6e3cfc70242205791e63f15e4 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Mon, 15 May 2023 19:30:48 +0200 Subject: [PATCH 3/9] minor fix to avoid the creation of '' templates since crow is incapable of routing those to / while trying to route them to / leading to a 404 obviously it's also possible to just give a general you have to name your template directive but as it stands i don't really see a need for it --- setupdb.sh | 2 +- src/main.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/setupdb.sh b/setupdb.sh index 23d3505..29f2eef 100644 --- a/setupdb.sh +++ b/setupdb.sh @@ -39,7 +39,7 @@ sudo -u postgres psql -c "CREATE TABLE freelancers( sudo -u postgres psql -c "CREATE TABLE templates( id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, freelancerID int, - name text, + name text NOT NULL, content text, contactData text, contactInformation text, diff --git a/src/main.cpp b/src/main.cpp index a5a1f21..63b7ba7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -699,7 +699,8 @@ int main(int argc, char *argv[]) { if (splitItem.at(0) == "templatepriceondeliver") priceondeliver = splitItem.at(1); } - + if (name.empty()) + name = "unnamed"; if (!Utilities::checkIfStrIsNumber(priceupfront)) priceupfront = "0"; if (!Utilities::checkIfStrIsNumber(priceondeliver)) From d9f3fd711c9b4edb3b49e41b0f4b37467cb905c6 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Mon, 15 May 2023 19:32:21 +0200 Subject: [PATCH 4/9] implement base template operations with the corresponding templates fully implement the delete operation todo:edit operation --- src/database.cpp | 11 +++ src/databaseStatementConstCollection.cpp | 14 +++- src/main.cpp | 78 ++++++++++++++++--- src/templateConstCollection.cpp | 5 +- ...gement_Fulfilment_Stage_Confirmation.html} | 4 +- ...Management_Fulfilment_Stage_Execution.html | 30 +++++++ 6 files changed, 128 insertions(+), 14 deletions(-) rename templates/{freelancer_Template_Management_Fulfilment.html => freelancer_Template_Management_Fulfilment_Stage_Confirmation.html} (95%) create mode 100644 templates/freelancer_Template_Management_Fulfilment_Stage_Execution.html diff --git a/src/database.cpp b/src/database.cpp index ac3abe5..4b6c323 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -575,6 +575,17 @@ namespace Database { return 0; } + /* + * Executes the prepared statement DELETE_FREELANCER_TEMPLATE + * Deletes a templated based on the id and validated with the freelancer email + * Takes an open pqxx::connection the template id and the freelancers email + */ + void executePreparedStatement_DELETE_FREELANCER_TEMPLATE(pqxx::connection &connection, int templateID, const std::string& freelancerEmail) { + pqxx::work work(connection); + work.exec_prepared(PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE, templateID, freelancerEmail); + work.commit(); + } + /* * 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 4053847..ec68e57 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -193,6 +193,12 @@ namespace DatabaseStatementConstCollection { 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);"; + /* + * Name and Statement for prepared statement to delete a template with ownership validation + */ + const static std::string PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE = "deleteFreelancerTemplate"; + const static std::string SQL_STATEMENT_DELETE_FREELANCER_TEMPLATE = "delete from templates where id = $1 and freelancerid = (select freelancers.id from freelancers where emailaddress = $2);"; + /* * IDs of prepared statements */ @@ -226,6 +232,8 @@ namespace DatabaseStatementConstCollection { 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; + const static int ID_DELETE_FREELANCER_TEMPLATE = 30; + const static int ID_EDIT_FREELANCER_TEMPLATE = 31; /* * Easy access to prepared statements via prepared statement name @@ -260,7 +268,8 @@ namespace DatabaseStatementConstCollection { {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_INSERT_FREELANCER_TEMPLATE, SQL_STATEMENT_INSERT_FREELANCER_TEMPLATE} + {PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE, SQL_STATEMENT_INSERT_FREELANCER_TEMPLATE}, + {PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE, SQL_STATEMENT_DELETE_FREELANCER_TEMPLATE} }; /* * Easy access to prepared statement name via int @@ -295,7 +304,8 @@ namespace DatabaseStatementConstCollection { {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_INSERT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE} + {ID_INSERT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE}, + {ID_DELETE_FREELANCER_TEMPLATE, PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE} }; /* diff --git a/src/main.cpp b/src/main.cpp index 63b7ba7..d728d0d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -765,7 +765,7 @@ int main(int argc, char *argv[]) { } ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; } - auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_FULFILMENT); + auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_FULFILMENT_STAGE_CONFIRMATION); return page.render(ctx); }); @@ -773,17 +773,77 @@ int main(int argc, char *argv[]) { * Execute Template Operation * todo:implement */ - CROW_ROUTE(app, "/freelancer/templateManagement/fulfilment").methods("POST"_method) - ([&, configuration](const crow::request& postRequest ) { + CROW_ROUTE(app, "/freelancer/templateManagement/fulfilment/").methods("POST"_method) + ([&, configuration](const crow::request& postRequest, string operation ) { 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; + bool operationEdit = false; + bool operationDelete = false; + bool error = false; + if (operation == MUSTACHE_FREELANCER_TEMPLATE_OPERATION_EDIT) { + operationEdit = true; + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_EDIT] = true; } - auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT); + else if (operation == MUSTACHE_FREELANCER_TEMPLATE_OPERATION_DELETE) { + operationDelete = true; + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_DELETE] = true; + } + else { + error = true; + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_ERROR] = true; + } + + if (!error) { + if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { + ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; + string freelancerEmail = cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL); + string postRequestBody = postRequest.body; + Utilities::decodeString(postRequestBody); + int templateid; + vector splitPostRequestBody = Utilities::splitStringIntoVector(postRequestBody, '&'); + for (const string& item : splitPostRequestBody) { + vector splitItem = Utilities::splitStringIntoVector(item, '='); + if (splitItem.at(0) == "templateid") + templateid = stoi(splitItem.at(1)); + } + pqxx::connection databaseConnection(configuration.databaseConnectionString); + if (operationEdit) { + //todo:implement Edit + string name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver; + Database::prepareStatement(databaseConnection, ID_EDIT_FREELANCER_TEMPLATE); + 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"; + + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_COMPLETE] = true; + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_EDIT] = true; + } else if (operationDelete) { + Database::prepareStatement(databaseConnection, ID_DELETE_FREELANCER_TEMPLATE); + Database::executePreparedStatement_DELETE_FREELANCER_TEMPLATE(databaseConnection, templateid, freelancerEmail); + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_COMPLETE] = true; + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_DELETE] = true; + } + } + } + auto page = crow::mustache::load(TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_FULFILMENT_STAGE_EXECUTION); return page.render(ctx); }); diff --git a/src/templateConstCollection.cpp b/src/templateConstCollection.cpp index ff6c3d1..2cf2292 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -25,7 +25,8 @@ namespace TemplateConstCollection { const static std::string TEMPLATE_FREELANCER_REDIRECT_PROFILE = "freelancer_Redirect_Profile.html"; 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_FULFILMENT_STAGE_CONFIRMATION = "freelancer_Template_Management_Fulfilment_Stage_Confirmation.html"; + const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_FULFILMENT_STAGE_EXECUTION = "freelancer_Template_Management_Fulfilment_Stage_Execution.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"; @@ -56,7 +57,9 @@ 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_OPERATION_COMPLETE = "TEMPLATE_OPERATION_COMPLETE"; const static std::string MUSTACHE_FREELANCER_TEMPLATE_CREATION_ERROR = "TEMPLATE_CREATION_ERROR"; + const static std::string MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_ERROR = "OPERATION_ERROR"; //Mustache Cookie variable names const static std::string MUSTACHE_COOKIE_LOGGED_IN = "COOKIE_LOGGED_IN"; diff --git a/templates/freelancer_Template_Management_Fulfilment.html b/templates/freelancer_Template_Management_Fulfilment_Stage_Confirmation.html similarity index 95% rename from templates/freelancer_Template_Management_Fulfilment.html rename to templates/freelancer_Template_Management_Fulfilment_Stage_Confirmation.html index b39d950..41ecb9b 100644 --- a/templates/freelancer_Template_Management_Fulfilment.html +++ b/templates/freelancer_Template_Management_Fulfilment_Stage_Confirmation.html @@ -24,7 +24,7 @@ {{/OPERATION_EDIT}} {{#OPERATION_EDIT}}
-
+


@@ -38,7 +38,7 @@ {{/OPERATION_EDIT}} {{#OPERATION_DELETE}}
- +

diff --git a/templates/freelancer_Template_Management_Fulfilment_Stage_Execution.html b/templates/freelancer_Template_Management_Fulfilment_Stage_Execution.html new file mode 100644 index 0000000..daaa8b1 --- /dev/null +++ b/templates/freelancer_Template_Management_Fulfilment_Stage_Execution.html @@ -0,0 +1,30 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{#TEMPLATE_OPERATION_COMPLETE}} + The + {{#OPERATION_EDIT}}Edit{{/OPERATION_EDIT}} + {{#OPERATION_DELETE}}Delete{{/OPERATION_DELETE}} + Operation has been completed. + {{/TEMPLATE_OPERATION_COMPLETE}} + {{#OPERATION_ERROR}} + The Operation has not been completed + {{/OPERATION_ERROR}} +
+
+ +
+
+ +
+
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file From 1620967c45729c872219c58414bda6642b709bf4 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Wed, 17 May 2023 18:39:32 +0200 Subject: [PATCH 5/9] implementation of the edit function for the template managment +minor typo fixes --- src/database.cpp | 16 ++++++++++++++-- src/databaseStatementConstCollection.cpp | 14 +++++++++++--- src/main.cpp | 16 ++++++++++++---- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/database.cpp b/src/database.cpp index 4b6c323..8ab7b74 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -308,7 +308,7 @@ namespace Database { /* * Executes the prepared statement SELECT_CHECK_EMAIL_EXISTS * Takes an open pqxx::connection and the emailAddress to check - * Delivers count of emailaddress occurence 0 for none 1+ for more + * Delivers count of emailaddress occurrence 0 for none 1+ for more */ pqxx::result executePreparedStatement_SELECT_CHECK_EMAIL_EXISTS(pqxx::connection &connection, const std::string& freelancerEmail) { pqxx::work work(connection); @@ -320,7 +320,7 @@ namespace Database { /* * Executes the prepared statement SELECT_CHECK_FREELANCER_LOGIN_STATE * Takes an open pqxx::connection the loginKey and the id to check - * Delivers count of loginValidationKey occurence 0 for none 1+ for more + * Delivers count of loginValidationKey occurrence 0 for none 1+ for more */ pqxx::result executePreparedStatement_SELECT_CHECK_FREELANCER_LOGIN_STATE(pqxx::connection &connection, const std::string& freelancerEmail, const std::string& loginKey) { pqxx::work work(connection); @@ -575,6 +575,18 @@ namespace Database { return 0; } + /* + * Executes the prepared statement UPDATE_EDIT_FREELANCER_TEMPLATE + * Takes an open pqxx::connection name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, templateid and the freelancers email + * returns true if update occured + */ + bool executePreparedStatement_UPDATE_EDIT_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, int templateid, const std::string& emailAddress) { + pqxx::work work(connection); + pqxx::result result = work.exec_prepared(PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE, name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, templateid, emailAddress); + work.commit(); + return result.affected_rows() != 0; + } + /* * Executes the prepared statement DELETE_FREELANCER_TEMPLATE * Deletes a templated based on the id and validated with the freelancer email diff --git a/src/databaseStatementConstCollection.cpp b/src/databaseStatementConstCollection.cpp index ec68e57..b552bc8 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -193,6 +193,12 @@ namespace DatabaseStatementConstCollection { 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);"; + /* + * Name and Statement for prepared statement to update the template of a freelancer + */ + const static std::string PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE = "updateEeditFreelancerTemplate"; + const static std::string SQL_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE = "UPDATE templates SET (name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver) = ($1, $2, $3, $4, $5, $6, $7) WHERE id = $8 and freelancerid = (select freelancers.id from freelancers where emailaddress = $9);"; + /* * Name and Statement for prepared statement to delete a template with ownership validation */ @@ -233,7 +239,7 @@ namespace DatabaseStatementConstCollection { const static int ID_UPDATE_EXPIRATION_LOGIN_LOCK_OUT = 28; const static int ID_INSERT_FREELANCER_TEMPLATE = 29; const static int ID_DELETE_FREELANCER_TEMPLATE = 30; - const static int ID_EDIT_FREELANCER_TEMPLATE = 31; + const static int ID_UPDATE_EDIT_FREELANCER_TEMPLATE = 31; /* * Easy access to prepared statements via prepared statement name @@ -269,7 +275,8 @@ namespace DatabaseStatementConstCollection { {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_INSERT_FREELANCER_TEMPLATE, SQL_STATEMENT_INSERT_FREELANCER_TEMPLATE}, - {PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE, SQL_STATEMENT_DELETE_FREELANCER_TEMPLATE} + {PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE, SQL_STATEMENT_DELETE_FREELANCER_TEMPLATE}, + {PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE, SQL_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE} }; /* * Easy access to prepared statement name via int @@ -305,7 +312,8 @@ namespace DatabaseStatementConstCollection { {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_INSERT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE}, - {ID_DELETE_FREELANCER_TEMPLATE, PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE} + {ID_DELETE_FREELANCER_TEMPLATE, PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE}, + {ID_UPDATE_EDIT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE} }; /* diff --git a/src/main.cpp b/src/main.cpp index d728d0d..2c631f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -808,9 +808,8 @@ int main(int argc, char *argv[]) { } pqxx::connection databaseConnection(configuration.databaseConnectionString); if (operationEdit) { - //todo:implement Edit string name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver; - Database::prepareStatement(databaseConnection, ID_EDIT_FREELANCER_TEMPLATE); + Database::prepareStatement(databaseConnection, ID_UPDATE_EDIT_FREELANCER_TEMPLATE); for (const string& item : splitPostRequestBody) { vector splitItem = Utilities::splitStringIntoVector(item, '='); if (splitItem.at(0) == "templatename") @@ -828,13 +827,22 @@ int main(int argc, char *argv[]) { if (splitItem.at(0) == "templatepriceondeliver") priceondeliver = splitItem.at(1); } + if (name.empty()) + name = "unnamed"; if (!Utilities::checkIfStrIsNumber(priceupfront)) priceupfront = "0"; if (!Utilities::checkIfStrIsNumber(priceondeliver)) priceondeliver = "0"; - ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_COMPLETE] = true; - ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_EDIT] = true; + bool updateSuccess = Database::executePreparedStatement_UPDATE_EDIT_FREELANCER_TEMPLATE(databaseConnection, name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, templateid, freelancerEmail); + + if (updateSuccess) { + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_COMPLETE] = true; + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_EDIT] = true; + } + else { + ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_ERROR] = true; + } } else if (operationDelete) { Database::prepareStatement(databaseConnection, ID_DELETE_FREELANCER_TEMPLATE); Database::executePreparedStatement_DELETE_FREELANCER_TEMPLATE(databaseConnection, templateid, freelancerEmail); From d83b4278579e087f122163d6f1881f38e420a395 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Fri, 19 May 2023 18:06:14 +0200 Subject: [PATCH 6/9] implement freelancer alias base management page and minor fixes --- src/database.cpp | 10 ++++++ src/databaseStatementConstCollection.cpp | 15 +++++++-- src/main.cpp | 19 +++++++++-- src/templateConstCollection.cpp | 1 + src/utilities.cpp | 13 ++++++++ templates/freelancer_Alias_Management.html | 39 ++++++++++++++++++++++ templates/freelancer_Profile.html | 2 +- 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 templates/freelancer_Alias_Management.html diff --git a/src/database.cpp b/src/database.cpp index 8ab7b74..3866e99 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -452,6 +452,16 @@ namespace Database { return result; } + /* + * Executes the prepared statement SELECT_FREELANCER_ALIAS + * Takes an open pqxx::connection and the freelancer email to select by + */ + pqxx::result executePreparedStatement_SELECT_FREELANCER_ALIAS(pqxx::connection &connection, const std::string& freelancerEmail) { + pqxx::work work(connection); + pqxx::result result = work.exec_prepared(PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS, freelancerEmail); + work.commit(); + return result; + } /* * Executes the prepared statement UPDATE_LOGIN_VALIDATION_KEY * Takes an open pqxx::connection, the freelancerID and the loginKey to update the entry diff --git a/src/databaseStatementConstCollection.cpp b/src/databaseStatementConstCollection.cpp index b552bc8..778e696 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -100,6 +100,12 @@ namespace DatabaseStatementConstCollection { const static std::string PREPARED_STATEMENT_SELECT_ALIAS = "selectAlias"; const static std::string SQL_STATEMENT_SELECT_ALIAS = "select aliasname, route, routeparameter, routevalue from aliasroutes where aliasname = $1;"; + /* + * Name and Statement for prepared statement to select an alias and its route via the alias name + */ + const static std::string PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS = "selectFreelancerAlias"; + const static std::string SQL_STATEMENT_SELECT_FREELANCER_ALIAS = "select aliasname, route from aliasroutes where freelancerid = (select freelancers.id from freelancers where emailaddress = $1);"; + /* * Name and Statement for prepared statement to update the loginvalidationkey of a freelancer via the freelancerID */ @@ -125,7 +131,7 @@ namespace DatabaseStatementConstCollection { const static std::string SQL_STATEMENT_SELECT_FREELANCER_EMAIL_FROM_PASSWORD_RESET_KEY = "select freelanceremail from passwordresetkeys where passwordresetkey = $1;"; /* - * Name and Statement for prepared statement to check if an reset key is expired + * Name and Statement for prepared statement to check if a reset key is expired * returns 0 if key not expired */ const static std::string PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_RESET_KEY_EXPIRED = "checkFreelancerResetKeyExpired"; @@ -240,6 +246,7 @@ namespace DatabaseStatementConstCollection { const static int ID_INSERT_FREELANCER_TEMPLATE = 29; const static int ID_DELETE_FREELANCER_TEMPLATE = 30; const static int ID_UPDATE_EDIT_FREELANCER_TEMPLATE = 31; + const static int ID_SELECT_FREELANCER_ALIAS = 32; /* * Easy access to prepared statements via prepared statement name @@ -276,7 +283,8 @@ namespace DatabaseStatementConstCollection { {PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT, SQL_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT}, {PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE, SQL_STATEMENT_INSERT_FREELANCER_TEMPLATE}, {PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE, SQL_STATEMENT_DELETE_FREELANCER_TEMPLATE}, - {PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE, SQL_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE} + {PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE, SQL_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE}, + {PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS, SQL_STATEMENT_SELECT_FREELANCER_ALIAS}, }; /* * Easy access to prepared statement name via int @@ -313,7 +321,8 @@ namespace DatabaseStatementConstCollection { {ID_UPDATE_EXPIRATION_LOGIN_LOCK_OUT, PREPARED_STATEMENT_UPDATE_EXPIRATION_LOGIN_LOCK_OUT}, {ID_INSERT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_INSERT_FREELANCER_TEMPLATE}, {ID_DELETE_FREELANCER_TEMPLATE, PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE}, - {ID_UPDATE_EDIT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE} + {ID_UPDATE_EDIT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE}, + {ID_SELECT_FREELANCER_ALIAS, PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS}, }; /* diff --git a/src/main.cpp b/src/main.cpp index 2c631f0..27af83d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { */ CROW_ROUTE(app, "/@") ([configuration](string alias) { - crow::mustache::context ctx(getAlias(configuration, alias)); + crow::mustache::context ctx(Utilities::getAlias(configuration, alias)); auto page = crow::mustache::load(TEMPLATE_ALIAS_REDIRECT); return page.render(ctx); }); @@ -771,7 +771,6 @@ int main(int argc, char *argv[]) { /* * Execute Template Operation - * todo:implement */ CROW_ROUTE(app, "/freelancer/templateManagement/fulfilment/").methods("POST"_method) ([&, configuration](const crow::request& postRequest, string operation ) { @@ -855,6 +854,22 @@ int main(int argc, char *argv[]) { return page.render(ctx); }); + /* + * Page for freelancer to create/delete Alias + */ + CROW_ROUTE(app, "/freelancer/aliasManagement") + ([&, configuration](const crow::request& getRequest ) { + auto& cookieCtx = app.get_context(getRequest); + crow::mustache::context ctx; + if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { + ctx = Utilities::getFreelancerAlias(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_ALIAS_MANAGEMENT); + return page.render(ctx); + }); + diff --git a/src/templateConstCollection.cpp b/src/templateConstCollection.cpp index 2cf2292..347cc46 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -29,6 +29,7 @@ namespace TemplateConstCollection { const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_FULFILMENT_STAGE_EXECUTION = "freelancer_Template_Management_Fulfilment_Stage_Execution.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"; + const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT = "freelancer_Alias_Management.html"; //Mustache Error/Success variable names const static std::string MUSTACHE_ERROR_COMMISSIONS_CLOSED = "ERROR_COMMISSIONS_CLOSED"; diff --git a/src/utilities.cpp b/src/utilities.cpp index eb536b4..f82ec11 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -523,6 +523,19 @@ namespace Utilities { return resultJsonFreelancerTemplate; } + /* + * Gets the freelancer alias and converts them into a wvalue JSON under the name "alias" + * takes config and freelancer email + */ + crow::json::wvalue getFreelancerAlias(const Utilities::config& configuration, const std::string& emailAddress) { + crow::json::wvalue resultJsonFreelancerAlias; + pqxx::connection databaseConnection(configuration.databaseConnectionString); + Database::prepareStatement(databaseConnection, ID_SELECT_FREELANCER_ALIAS); + pqxx::result aliasResult = Database::executePreparedStatement_SELECT_FREELANCER_ALIAS(databaseConnection, emailAddress); + resultJsonFreelancerAlias = Database::convertResultToJSON(aliasResult, "alias"); + return resultJsonFreelancerAlias; + } + /* * Checks if a given string is a valid number */ diff --git a/templates/freelancer_Alias_Management.html b/templates/freelancer_Alias_Management.html new file mode 100644 index 0000000..ab053ac --- /dev/null +++ b/templates/freelancer_Alias_Management.html @@ -0,0 +1,39 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{^COOKIE_LOGGED_IN}} + Please Log in. + {{/COOKIE_LOGGED_IN}} + {{#COOKIE_LOGGED_IN}} +

Freelancer: {{freelanceremail}}

+
+
+ + {{#alias}} + + + + + + {{/alias}} +
@{{aliasname}}{{route}} +
+ +
+
+
+ +
+ {{/COOKIE_LOGGED_IN}} + {{> templateIncludes/freelancerLoginSignupProfileLogoutInterface.html.html}} +
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file diff --git a/templates/freelancer_Profile.html b/templates/freelancer_Profile.html index 63a6943..45cd2ca 100644 --- a/templates/freelancer_Profile.html +++ b/templates/freelancer_Profile.html @@ -28,7 +28,7 @@
-
+
From bfddfd52716fd903a86ba041b61508d48a6a694d Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Fri, 19 May 2023 18:10:31 +0200 Subject: [PATCH 7/9] implement freelancer alias deletion --- src/database.cpp | 12 ++++++++ src/databaseStatementConstCollection.cpp | 8 ++++++ src/main.cpp | 25 +++++++++++++++++ src/templateConstCollection.cpp | 1 + src/utilities.cpp | 9 ++++++ .../freelancer_Alias_Management_Delete.html | 28 +++++++++++++++++++ 6 files changed, 83 insertions(+) create mode 100644 templates/freelancer_Alias_Management_Delete.html diff --git a/src/database.cpp b/src/database.cpp index 3866e99..6de5330 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -462,6 +462,18 @@ namespace Database { work.commit(); return result; } + + /* + * Executes the prepared statement DELETE_FREELANCER_ALIAS + * Deletes the entry for a reset key based on a freelancer email and the alias name + * Takes an open pqxx::connection and the freelancers email + */ + void executePreparedStatement_DELETE_FREELANCER_ALIAS(pqxx::connection &connection, const std::string& aliasName, const std::string& freelancerEmail) { + pqxx::work work(connection); + work.exec_prepared(PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS, aliasName, freelancerEmail); + work.commit(); + } + /* * Executes the prepared statement UPDATE_LOGIN_VALIDATION_KEY * Takes an open pqxx::connection, the freelancerID and the loginKey to update the entry diff --git a/src/databaseStatementConstCollection.cpp b/src/databaseStatementConstCollection.cpp index 778e696..e7c9e7e 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -106,6 +106,11 @@ namespace DatabaseStatementConstCollection { const static std::string PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS = "selectFreelancerAlias"; const static std::string SQL_STATEMENT_SELECT_FREELANCER_ALIAS = "select aliasname, route from aliasroutes where freelancerid = (select freelancers.id from freelancers where emailaddress = $1);"; + /* + * Name and Statement for prepared statement to select an alias and its route via the alias name + */ + const static std::string PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS = "deleteFreelancerAlias"; + const static std::string SQL_STATEMENT_DELETE_FREELANCER_ALIAS = "delete from aliasroutes where aliasname = $1 and freelancerid = (select freelancers.id from freelancers where emailaddress = $2);"; /* * Name and Statement for prepared statement to update the loginvalidationkey of a freelancer via the freelancerID */ @@ -247,6 +252,7 @@ namespace DatabaseStatementConstCollection { const static int ID_DELETE_FREELANCER_TEMPLATE = 30; const static int ID_UPDATE_EDIT_FREELANCER_TEMPLATE = 31; const static int ID_SELECT_FREELANCER_ALIAS = 32; + const static int ID_DELETE_FREELANCER_ALIAS = 33; /* * Easy access to prepared statements via prepared statement name @@ -285,6 +291,7 @@ namespace DatabaseStatementConstCollection { {PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE, SQL_STATEMENT_DELETE_FREELANCER_TEMPLATE}, {PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE, SQL_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE}, {PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS, SQL_STATEMENT_SELECT_FREELANCER_ALIAS}, + {PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS, SQL_STATEMENT_DELETE_FREELANCER_ALIAS}, }; /* * Easy access to prepared statement name via int @@ -323,6 +330,7 @@ namespace DatabaseStatementConstCollection { {ID_DELETE_FREELANCER_TEMPLATE, PREPARED_STATEMENT_DELETE_FREELANCER_TEMPLATE}, {ID_UPDATE_EDIT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE}, {ID_SELECT_FREELANCER_ALIAS, PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS}, + {ID_DELETE_FREELANCER_ALIAS, PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS}, }; /* diff --git a/src/main.cpp b/src/main.cpp index 27af83d..b542b39 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -870,6 +870,31 @@ int main(int argc, char *argv[]) { return page.render(ctx); }); + /* + * Execute Alias deletion + */ + CROW_ROUTE(app, "/freelancer/aliasManagement/delete").methods("POST"_method) + ([&, configuration](const crow::request& postRequest) { + auto& cookieCtx = app.get_context(postRequest); + crow::mustache::context ctx; + if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { + string postRequestBody = postRequest.body; + Utilities::decodeString(postRequestBody); + string aliasName; + vector splitPostRequestBody = Utilities::splitStringIntoVector(postRequestBody, '&'); + for (const string& item : splitPostRequestBody) { + vector splitItem = Utilities::splitStringIntoVector(item, '='); + if (splitItem.at(0) == "alias") + aliasName = splitItem.at(1); + } + Utilities::deleteFreelancerAlias(configuration, aliasName, 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_ALIAS_MANAGEMENT_DELETE); + return page.render(ctx); + }); + diff --git a/src/templateConstCollection.cpp b/src/templateConstCollection.cpp index 347cc46..a89f9df 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -30,6 +30,7 @@ namespace TemplateConstCollection { 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"; const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT = "freelancer_Alias_Management.html"; + const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT_DELETE = "freelancer_Alias_Management_Delete.html"; //Mustache Error/Success variable names const static std::string MUSTACHE_ERROR_COMMISSIONS_CLOSED = "ERROR_COMMISSIONS_CLOSED"; diff --git a/src/utilities.cpp b/src/utilities.cpp index f82ec11..3645c54 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -536,6 +536,15 @@ namespace Utilities { return resultJsonFreelancerAlias; } + /* + * Deletes a freelancers alias + * takes config the alias name and the freelancers email + */ + void deleteFreelancerAlias(const Utilities::config& configuration, const std::string& aliasName, const std::string& emailAddress) { + pqxx::connection databaseConnection(configuration.databaseConnectionString); + Database::prepareStatement(databaseConnection, ID_DELETE_FREELANCER_ALIAS); + Database::executePreparedStatement_DELETE_FREELANCER_ALIAS(databaseConnection, aliasName, emailAddress); + } /* * Checks if a given string is a valid number */ diff --git a/templates/freelancer_Alias_Management_Delete.html b/templates/freelancer_Alias_Management_Delete.html new file mode 100644 index 0000000..011dbe7 --- /dev/null +++ b/templates/freelancer_Alias_Management_Delete.html @@ -0,0 +1,28 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{^COOKIE_LOGGED_IN}} + Please Log in. + {{/COOKIE_LOGGED_IN}} + {{#COOKIE_LOGGED_IN}} + Operation concluded: +
+
+ +
+
+ +
+ {{/COOKIE_LOGGED_IN}} + {{> templateIncludes/freelancerLoginSignupProfileLogoutInterface.html.html}} +
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file From 549c98f67308b172fa26e72f5d8095162d256773 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Fri, 19 May 2023 18:10:52 +0200 Subject: [PATCH 8/9] implement freelancer alias creation --- src/database.cpp | 53 +++++++++++- src/databaseStatementConstCollection.cpp | 29 +++++++ src/main.cpp | 85 +++++++++++++++++++ src/templateConstCollection.cpp | 5 ++ src/utilities.cpp | 25 +++++- .../freelancer_Alias_Management_New.html | 32 +++++++ ...ancer_Alias_Management_New_Fulfilment.html | 42 +++++++++ 7 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 templates/freelancer_Alias_Management_New.html create mode 100644 templates/freelancer_Alias_Management_New_Fulfilment.html diff --git a/src/database.cpp b/src/database.cpp index 6de5330..1083393 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -296,7 +296,7 @@ namespace Database { /* * Executes the prepared statement SELECT_FREELANCER_ID - * Takes an open pqxx::connection and the id to select by + * Takes an open pqxx::connection and the email to select by */ pqxx::result executePreparedStatement_SELECT_FREELANCER_ID(pqxx::connection &connection, const std::string& freelancerEmail) { pqxx::work work(connection); @@ -305,6 +305,17 @@ namespace Database { return result; } + /* + * Executes the prepared statement SELECT_FREELANCER_NAME + * Takes an open pqxx::connection and the email to select by + */ + pqxx::result executePreparedStatement_SELECT_FREELANCER_NAME(pqxx::connection &connection, const std::string& freelancerEmail) { + pqxx::work work(connection); + pqxx::result result = work.exec_prepared(PREPARED_STATEMENT_SELECT_FREELANCER_NAME, freelancerEmail); + work.commit(); + return result; + } + /* * Executes the prepared statement SELECT_CHECK_EMAIL_EXISTS * Takes an open pqxx::connection and the emailAddress to check @@ -452,6 +463,33 @@ namespace Database { return result; } + /* + * Executes the prepared statement INSERT_FREELANCER_ALIAS + * Takes an open pqxx::connection and aliasname, freelanceremail, route, routeparameter, routevalue + * returns errorLevel + * 0 = no error + * 1 = query error + * 2 = critical error + */ + int executePreparedStatement_INSERT_FREELANCER_ALIAS(pqxx::connection &connection, const std::string& aliasname, const std::string& freelanceremail, const std::string& route, const std::string& routeparameter, const std::string& routevalue) { + try { + pqxx::work work(connection); + work.exec_prepared(PREPARED_STATEMENT_INSERT_FREELANCER_ALIAS, aliasname, freelanceremail, route, routeparameter, routevalue); + 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; + } + /* * Executes the prepared statement SELECT_FREELANCER_ALIAS * Takes an open pqxx::connection and the freelancer email to select by @@ -474,6 +512,19 @@ namespace Database { work.commit(); } + /* + * Executes the prepared statement SELECT_CHECK_FREELANCER_ALIAS + * Takes an open pqxx::connection and the alias name + * Delivers true if the alias is already used + */ + bool executePreparedStatement_SELECT_CHECK_FREELANCER_ALIAS(pqxx::connection &connection, const std::string& aliasName) { + pqxx::work work(connection); + pqxx::result result = work.exec_prepared(PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_ALIAS, aliasName); + work.commit(); + std::string extractedResult = result.at(0).at(0).c_str(); + return extractedResult == "t"; + } + /* * Executes the prepared statement UPDATE_LOGIN_VALIDATION_KEY * Takes an open pqxx::connection, the freelancerID and the loginKey to update the entry diff --git a/src/databaseStatementConstCollection.cpp b/src/databaseStatementConstCollection.cpp index e7c9e7e..f73c5f0 100644 --- a/src/databaseStatementConstCollection.cpp +++ b/src/databaseStatementConstCollection.cpp @@ -58,12 +58,19 @@ namespace DatabaseStatementConstCollection { */ const static std::string PREPARED_STATEMENT_SELECT_FREELANCER_SALT = "selectFreelancerSalt"; const static std::string SQL_STATEMENT_SELECT_FREELANCER_SALT = "select salt from freelancers where emailaddress = $1;"; + /* * Name and Statement for prepared statement to get id using a given email */ const static std::string PREPARED_STATEMENT_SELECT_FREELANCER_ID = "selectFreelancerID"; const static std::string SQL_STATEMENT_SELECT_FREELANCER_ID = "select id from freelancers where emailaddress = $1;"; + /* + * Name and Statement for prepared statement to get name using a given email + */ + const static std::string PREPARED_STATEMENT_SELECT_FREELANCER_NAME = "selectFreelancerName"; + const static std::string SQL_STATEMENT_SELECT_FREELANCER_NAME = "select name from freelancers where emailaddress = $1;"; + /* * Name and Statement for prepared statement to check if hash is valid */ @@ -111,6 +118,19 @@ namespace DatabaseStatementConstCollection { */ const static std::string PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS = "deleteFreelancerAlias"; const static std::string SQL_STATEMENT_DELETE_FREELANCER_ALIAS = "delete from aliasroutes where aliasname = $1 and freelancerid = (select freelancers.id from freelancers where emailaddress = $2);"; + + /* + * Name and Statement for prepared statement to select an alias and its route via the alias name + */ + const static std::string PREPARED_STATEMENT_INSERT_FREELANCER_ALIAS = "insertFreelancerAlias"; + const static std::string SQL_STATEMENT_INSERT_FREELANCER_ALIAS = "insert into aliasroutes (aliasname, freelancerid, route, routeparameter, routevalue) VALUES($1, (select freelancers.id from freelancers where emailaddress = $2), $3, $4, $5);"; + + /* + * Name and Statement for prepared statement to try to check if an alias already exists + */ + const static std::string PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_ALIAS = "selectCheckFreelancerAlias"; + const static std::string SQL_STATEMENT_SELECT_CHECK_FREELANCER_ALIAS = "select count(*) = 1 from aliasroutes where aliasname = $1;"; + /* * Name and Statement for prepared statement to update the loginvalidationkey of a freelancer via the freelancerID */ @@ -253,6 +273,9 @@ namespace DatabaseStatementConstCollection { const static int ID_UPDATE_EDIT_FREELANCER_TEMPLATE = 31; const static int ID_SELECT_FREELANCER_ALIAS = 32; const static int ID_DELETE_FREELANCER_ALIAS = 33; + const static int ID_INSERT_FREELANCER_ALIAS = 34; + const static int ID_SELECT_CHECK_FREELANCER_ALIAS = 35; + const static int ID_SELECT_FREELANCER_NAME = 36; /* * Easy access to prepared statements via prepared statement name @@ -292,6 +315,9 @@ namespace DatabaseStatementConstCollection { {PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE, SQL_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE}, {PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS, SQL_STATEMENT_SELECT_FREELANCER_ALIAS}, {PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS, SQL_STATEMENT_DELETE_FREELANCER_ALIAS}, + {PREPARED_STATEMENT_INSERT_FREELANCER_ALIAS, SQL_STATEMENT_INSERT_FREELANCER_ALIAS}, + {PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_ALIAS, SQL_STATEMENT_SELECT_CHECK_FREELANCER_ALIAS}, + {PREPARED_STATEMENT_SELECT_FREELANCER_NAME, SQL_STATEMENT_SELECT_FREELANCER_NAME} }; /* * Easy access to prepared statement name via int @@ -331,6 +357,9 @@ namespace DatabaseStatementConstCollection { {ID_UPDATE_EDIT_FREELANCER_TEMPLATE, PREPARED_STATEMENT_UPDATE_EDIT_FREELANCER_TEMPLATE}, {ID_SELECT_FREELANCER_ALIAS, PREPARED_STATEMENT_SELECT_FREELANCER_ALIAS}, {ID_DELETE_FREELANCER_ALIAS, PREPARED_STATEMENT_DELETE_FREELANCER_ALIAS}, + {ID_INSERT_FREELANCER_ALIAS, PREPARED_STATEMENT_INSERT_FREELANCER_ALIAS}, + {ID_SELECT_CHECK_FREELANCER_ALIAS, PREPARED_STATEMENT_SELECT_CHECK_FREELANCER_ALIAS}, + {ID_SELECT_FREELANCER_NAME, PREPARED_STATEMENT_SELECT_FREELANCER_NAME} }; /* diff --git a/src/main.cpp b/src/main.cpp index b542b39..de19411 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -895,6 +895,91 @@ int main(int argc, char *argv[]) { return page.render(ctx); }); + /* + * Page for freelancer to create alias + */ + CROW_ROUTE(app, "/freelancer/aliasManagement/new") + ([&, configuration](const crow::request& getRequest ) { + auto& cookieCtx = app.get_context(getRequest); + 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_ALIAS_MANAGEMENT_NEW); + return page.render(ctx); + }); + + /* + * Execute alias creation + */ + CROW_ROUTE(app, "/freelancer/aliasManagement/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)) { + bool error = false; + ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; + string postRequestBody = postRequest.body; + Utilities::decodeString(postRequestBody); + vector splitPostRequestBody = Utilities::splitStringIntoVector(postRequestBody, '&'); + string aliasname, templateNameID, templateName; + for (const string& item : splitPostRequestBody) { + vector splitItem = Utilities::splitStringIntoVector(item, '='); + if (splitItem.at(0) == "freelanceralias") + aliasname = splitItem.at(1); + if (splitItem.at(0) == "aliasroute") + templateNameID = splitItem.at(1); + } + + pqxx::connection databaseConnection(configuration.databaseConnectionString); + Database::prepareStatements(databaseConnection, { + ID_SELECT_CHECK_FREELANCER_ALIAS, + ID_INSERT_FREELANCER_ALIAS, + ID_SELECT_FREELANCER_ID, + ID_SELECT_FREELANCER_NAME + }); + + bool aliasAlreadyUsed = false; + if (aliasname.empty()) { + error = true; + ctx[MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR] = true; + ctx[MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR_UNNAMED] = true; + } else { + ctx["aliasname"] = aliasname; + aliasAlreadyUsed = Database::executePreparedStatement_SELECT_CHECK_FREELANCER_ALIAS(databaseConnection, aliasname); + } + if (aliasAlreadyUsed) { + error = true; + ctx[MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR] = true; + ctx[MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR_DUPLICATE] = true; + } + if (!error) { + string route, routeparameter, routevalue; + pqxx::result freelancerNameResult = Database::executePreparedStatement_SELECT_FREELANCER_NAME(databaseConnection, cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL)); + if (templateNameID.empty()) { + routeparameter = "freelancerID"; + pqxx::result freelancerIDResult = Database::executePreparedStatement_SELECT_FREELANCER_ID(databaseConnection, cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL)); + routevalue = freelancerIDResult.at(0).at(0).c_str(); + route = Utilities::generateAliasRouteFreelancer(freelancerNameResult.at(0).at(0).c_str()); + + } else { + routeparameter = "templateID"; + vector splitValues = Utilities::splitStringIntoVector(templateNameID, '|'); + routevalue = splitValues.at(1); + route = Utilities::generateAliasRouteFreelancerTemplate(freelancerNameResult.at(0).at(0).c_str(), splitValues.at(0)); + } + int errorLevel = Database::executePreparedStatement_INSERT_FREELANCER_ALIAS(databaseConnection, aliasname, cookieCtx.get_cookie(COOKIE_FREELANCER_EMAIL), route, routeparameter, routevalue); + ctx["aliasname"] = aliasname; + if (errorLevel != 0) + ctx[MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR] = true; + } + } + auto page = crow::mustache::load(TEMPLATE_FREELANCER_ALIAS_MANAGEMENT_NEW_FULFILMENT); + return page.render(ctx); + }); + diff --git a/src/templateConstCollection.cpp b/src/templateConstCollection.cpp index a89f9df..6284602 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -31,6 +31,8 @@ namespace TemplateConstCollection { const static std::string TEMPLATE_FREELANCER_TEMPLATE_MANAGEMENT_CREATE_NEW_FULFILMENT = "freelancer_Template_Management_Create_New_Fulfilment.html"; const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT = "freelancer_Alias_Management.html"; const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT_DELETE = "freelancer_Alias_Management_Delete.html"; + const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT_NEW = "freelancer_Alias_Management_New.html"; + const static std::string TEMPLATE_FREELANCER_ALIAS_MANAGEMENT_NEW_FULFILMENT = "freelancer_Alias_Management_New_Fulfilment.html"; //Mustache Error/Success variable names const static std::string MUSTACHE_ERROR_COMMISSIONS_CLOSED = "ERROR_COMMISSIONS_CLOSED"; @@ -62,6 +64,9 @@ namespace TemplateConstCollection { const static std::string MUSTACHE_FREELANCER_TEMPLATE_OPERATION_COMPLETE = "TEMPLATE_OPERATION_COMPLETE"; const static std::string MUSTACHE_FREELANCER_TEMPLATE_CREATION_ERROR = "TEMPLATE_CREATION_ERROR"; const static std::string MUSTACHE_FREELANCER_TEMPLATE_OPERATION_FULFILMENT_ERROR = "OPERATION_ERROR"; + const static std::string MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR = "ALIAS_CREATION_ERROR"; + const static std::string MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR_DUPLICATE = "ALIAS_CREATION_ERROR_DUPLICATE"; + const static std::string MUSTACHE_FREELANCER_ALIAS_CREATION_ERROR_UNNAMED = "ALIAS_CREATION_ERROR_UNNAMED"; //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 3645c54..d634007 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -359,9 +359,11 @@ namespace Utilities { * returns crow::json::wvalue with the Alias */ crow::json::wvalue getAlias(const Utilities::config& configuration, const std::string& alias) { + std::string decodedAlias = alias; + decodeString(decodedAlias); pqxx::connection databaseConnection(configuration.databaseConnectionString); Database::prepareStatement(databaseConnection, ID_SELECT_ALIAS); - pqxx::result resultAlias = Database::executePreparedStatement_SELECT_ALIAS(databaseConnection, alias); + pqxx::result resultAlias = Database::executePreparedStatement_SELECT_ALIAS(databaseConnection, decodedAlias); crow::json::wvalue resultJsonAlias; if (!resultAlias.empty()) resultJsonAlias = Database::convertResultRowToJSON(resultAlias); @@ -505,6 +507,10 @@ namespace Utilities { } } + /* + * Gets the freelancer templates and converts them into a wvalue JSON under the name "templates" + * takes config and freelancer email + */ crow::json::wvalue getFreelancerTemplates(const Utilities::config& configuration, const std::string& emailAddress) { crow::json::wvalue resultJsonFreelancerTemplate; @@ -545,6 +551,23 @@ namespace Utilities { Database::prepareStatement(databaseConnection, ID_DELETE_FREELANCER_ALIAS); Database::executePreparedStatement_DELETE_FREELANCER_ALIAS(databaseConnection, aliasName, emailAddress); } + + /* + * Generates an alias route to the freelancers profile + * takes a freelancers name + */ + std::string generateAliasRouteFreelancer(const std::string& freelancerName) { + return "/customer/" + freelancerName; + } + + /* + * Generates an alias route to the freelancers template + * takes a freelancers and a templates name + */ + std::string generateAliasRouteFreelancerTemplate(const std::string& freelancerName, const std::string& templateName) { + return "/customer/" + freelancerName + "/template/" + templateName; + } + /* * Checks if a given string is a valid number */ diff --git a/templates/freelancer_Alias_Management_New.html b/templates/freelancer_Alias_Management_New.html new file mode 100644 index 0000000..a404b7a --- /dev/null +++ b/templates/freelancer_Alias_Management_New.html @@ -0,0 +1,32 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{^COOKIE_LOGGED_IN}} + Please Log in. + {{/COOKIE_LOGGED_IN}} + {{#COOKIE_LOGGED_IN}} +

Freelancer: {{freelanceremail}}

+
+
+
+
+ +
+ {{/COOKIE_LOGGED_IN}} + {{> templateIncludes/freelancerLoginSignupProfileLogoutInterface.html.html}} +
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file diff --git a/templates/freelancer_Alias_Management_New_Fulfilment.html b/templates/freelancer_Alias_Management_New_Fulfilment.html new file mode 100644 index 0000000..23912ae --- /dev/null +++ b/templates/freelancer_Alias_Management_New_Fulfilment.html @@ -0,0 +1,42 @@ + + + + {{> templateIncludes/style.css.html}} + + + {{^COOKIE_LOGGED_IN}} + Please Log in. + {{/COOKIE_LOGGED_IN}} + {{#COOKIE_LOGGED_IN}} + {{^ALIAS_CREATION_ERROR}} + Alias has been created: +
+ +
+ {{/ALIAS_CREATION_ERROR}} + {{#ALIAS_CREATION_ERROR}} + Alias has not been created: + {{#ALIAS_CREATION_ERROR_DUPLICATE}} + Alias with the chosen name (@{{aliasname}}) already exists. + {{/ALIAS_CREATION_ERROR_DUPLICATE}} + {{#ALIAS_CREATION_ERROR_UNNAMED}} + Alias can not be created without a name. + {{/ALIAS_CREATION_ERROR_UNNAMED}} + {{/ALIAS_CREATION_ERROR}} + +
+ +
+
+ +
+ {{/COOKIE_LOGGED_IN}} + {{> templateIncludes/freelancerLoginSignupProfileLogoutInterface.html.html}} +
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file From 9e5f0a68ab1ab84f7f8585722f4c9df63054a672 Mon Sep 17 00:00:00 2001 From: Tina_Azure <-> Date: Mon, 22 May 2023 17:04:41 +0200 Subject: [PATCH 9/9] Optimize template edit/creation requestbody parsing --- src/main.cpp | 85 +++++++++++++---------------------------------- src/utilities.cpp | 74 +++++++++++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 75 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index de19411..f491fe9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -676,49 +676,27 @@ int main(int argc, char *argv[]) { crow::mustache::context ctx; if (Utilities::checkCookieLoginState(configuration, cookieCtx)) { ctx[MUSTACHE_COOKIE_LOGGED_IN] = true; - string name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver; + + Utilities::templateItem newTemplate; 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 (name.empty()) - name = "unnamed"; - if (!Utilities::checkIfStrIsNumber(priceupfront)) - priceupfront = "0"; - if (!Utilities::checkIfStrIsNumber(priceondeliver)) - priceondeliver = "0"; - + newTemplate.parseRequestBodyIntoItem(postRequestBody); + newTemplate.outputItem(); 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)); + databaseConnection, newTemplate.name, newTemplate.content, newTemplate.contactdata, newTemplate.contactinformation, + newTemplate.currencypreference, newTemplate.priceupfront, newTemplate.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; + ctx["templatename"] = newTemplate.name; + ctx["contactdata"] = newTemplate.contactdata; + ctx["contactinformation"] = newTemplate.contactinformation; + ctx["currencypreference"] = newTemplate.currencypreference; + ctx["priceupfront"] = newTemplate.priceupfront; + ctx["priceondeliver"] = newTemplate.priceondeliver; + ctx["content"] = newTemplate.content; } else { ctx[MUSTACHE_FREELANCER_TEMPLATE_CREATION_ERROR] = true; @@ -802,38 +780,21 @@ int main(int argc, char *argv[]) { vector splitPostRequestBody = Utilities::splitStringIntoVector(postRequestBody, '&'); for (const string& item : splitPostRequestBody) { vector splitItem = Utilities::splitStringIntoVector(item, '='); - if (splitItem.at(0) == "templateid") - templateid = stoi(splitItem.at(1)); + if (splitItem[0] == "templateid") { + templateid = stoi(splitItem[1]); + break; + } } pqxx::connection databaseConnection(configuration.databaseConnectionString); if (operationEdit) { - string name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver; + Utilities::templateItem toEditTemplate; Database::prepareStatement(databaseConnection, ID_UPDATE_EDIT_FREELANCER_TEMPLATE); - 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 (name.empty()) - name = "unnamed"; - if (!Utilities::checkIfStrIsNumber(priceupfront)) - priceupfront = "0"; - if (!Utilities::checkIfStrIsNumber(priceondeliver)) - priceondeliver = "0"; + toEditTemplate.parseRequestBodyIntoItem(postRequestBody); + toEditTemplate.outputItem(); - bool updateSuccess = Database::executePreparedStatement_UPDATE_EDIT_FREELANCER_TEMPLATE(databaseConnection, name, content, contactdata, contactinformation, currencypreference, priceupfront, priceondeliver, templateid, freelancerEmail); + bool updateSuccess = Database::executePreparedStatement_UPDATE_EDIT_FREELANCER_TEMPLATE( + databaseConnection, toEditTemplate.name, toEditTemplate.content, toEditTemplate.contactdata, toEditTemplate.contactinformation, + toEditTemplate.currencypreference, toEditTemplate.priceupfront, toEditTemplate.priceondeliver, templateid, freelancerEmail); if (updateSuccess) { ctx[MUSTACHE_FREELANCER_TEMPLATE_OPERATION_COMPLETE] = true; diff --git a/src/utilities.cpp b/src/utilities.cpp index d634007..5162b7e 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -59,6 +59,19 @@ namespace Utilities { return stringToTrim; } + /* + * 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; + } + /* * Struct representing the configuration file */ @@ -227,6 +240,54 @@ namespace Utilities { } }; + /* + * Struct representing a freelancers template + */ + struct templateItem { + std::string name; + std::string content; + std::string contactdata; + std::string contactinformation; + std::string currencypreference; + std::string priceupfront; + std::string priceondeliver; + + /* + * Parses a decoded request body string and fills the struct + */ + void parseRequestBodyIntoItem(const std::string& requestBody) { + std::vector splitPostRequestBody = Utilities::splitStringIntoVector(requestBody, '&'); + for (const std::string& item : splitPostRequestBody) { + std::vector splitItem = Utilities::splitStringIntoVector(item, '='); + if (splitItem[0] == "templatename") + name = splitItem[1]; + if (splitItem[0] == "templatecontent") + content = splitItem[1]; + if (splitItem[0] == "templatecontactdata") + contactdata = splitItem[1]; + if (splitItem[0] == "templatecontactinformation") + contactinformation = splitItem[1]; + if (splitItem[0] == "templatecurrencypreference") + currencypreference = splitItem[1]; + if (splitItem[0] == "templatepriceupfront") + priceupfront = splitItem[1]; + if (splitItem[0] == "templatepriceondeliver") + priceondeliver = splitItem[1]; + } + if (name.empty()) + name = "unnamed"; + if (!checkIfStrIsNumber(priceupfront)) + priceupfront = "0"; + if (!checkIfStrIsNumber(priceondeliver)) + priceondeliver = "0"; + } + + void outputItem() { + std::cout << name << " " << content << " " << contactdata << " " << contactinformation << " " << currencypreference + << " " << priceupfront << "-" << priceondeliver << " " << std::endl; + } + }; + /* * Takes String and cuts from the start-up to the length of valueName */ @@ -567,18 +628,5 @@ namespace Utilities { std::string generateAliasRouteFreelancerTemplate(const std::string& freelancerName, const std::string& templateName) { return "/customer/" + freelancerName + "/template/" + templateName; } - - /* - * 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