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