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/database.cpp b/src/database.cpp index de1b2b3..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,10 +305,21 @@ 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 - * 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 +331,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); @@ -452,6 +463,68 @@ 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 + */ + 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 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 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 @@ -548,6 +621,56 @@ 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; + } + + /* + * 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 + * 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 747319d..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 */ @@ -100,6 +107,30 @@ 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 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 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 */ @@ -125,7 +156,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"; @@ -186,6 +217,25 @@ 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);"; + + /* + * 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 + */ + 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 */ @@ -218,6 +268,14 @@ 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; + 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; + 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 @@ -251,7 +309,15 @@ 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}, + {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}, + {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 @@ -285,7 +351,15 @@ 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}, + {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}, + {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 83a49a1..f491fe9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include @@ -72,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); }); @@ -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,60 @@ 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; + + Utilities::templateItem newTemplate; + + string postRequestBody = postRequest.body; + Utilities::decodeString(postRequestBody); + 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, 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"] = 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; + } + } + 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 ) { @@ -691,11 +743,203 @@ 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); }); + /* + * Execute Template Operation + */ + CROW_ROUTE(app, "/freelancer/templateManagement/fulfilment/").methods("POST"_method) + ([&, configuration](const crow::request& postRequest, string operation ) { + auto& cookieCtx = app.get_context(postRequest); + crow::mustache::context ctx; + 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; + } + 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[0] == "templateid") { + templateid = stoi(splitItem[1]); + break; + } + } + pqxx::connection databaseConnection(configuration.databaseConnectionString); + if (operationEdit) { + Utilities::templateItem toEditTemplate; + Database::prepareStatement(databaseConnection, ID_UPDATE_EDIT_FREELANCER_TEMPLATE); + toEditTemplate.parseRequestBodyIntoItem(postRequestBody); + toEditTemplate.outputItem(); + + 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; + 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); + 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); + }); + + /* + * 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); + }); + + /* + * 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); + }); + + /* + * 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 a456c99..6284602 100644 --- a/src/templateConstCollection.cpp +++ b/src/templateConstCollection.cpp @@ -25,7 +25,14 @@ 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"; + 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"; @@ -54,6 +61,12 @@ 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"; + 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 14d39ac..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 */ @@ -359,9 +420,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 +568,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; @@ -522,5 +589,44 @@ 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; + } + + /* + * 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); + } + + /* + * 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; + } } #endif \ No newline at end of file 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_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 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 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 @@
-
+
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_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 diff --git a/templates/freelancer_Template_Management_Fulfilment.html b/templates/freelancer_Template_Management_Fulfilment.html deleted file mode 100644 index cb1716c..0000000 --- a/templates/freelancer_Template_Management_Fulfilment.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - {{> templateIncludes/style.css.html}} - - -

Freelancer: {{freelancername}}

-

Template: {{templatename}}

-
Contact Information:
-
- {{contactdata}}
- {{contactinformation}} -
-
-
Payment Information:
-
- Prefered Currency: {{currencypreference}}
- Price: {{pricetotal}} - Upfront: {{priceupfront}} - On Delivery: {{priceondeliver}}
-
-
-
Description:
-
{{content}}
-
-
- -
-
- -
-
- {{> templateIncludes/returnToIndexButton.html.html}} - - - - - - \ No newline at end of file diff --git a/templates/freelancer_Template_Management_Fulfilment_Stage_Confirmation.html b/templates/freelancer_Template_Management_Fulfilment_Stage_Confirmation.html new file mode 100644 index 0000000..41ecb9b --- /dev/null +++ b/templates/freelancer_Template_Management_Fulfilment_Stage_Confirmation.html @@ -0,0 +1,65 @@ + + + + {{> templateIncludes/style.css.html}} + + +

Freelancer: {{freelancername}}

+ {{^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}} +
+
+ +
+
+ +
+
+ {{> templateIncludes/returnToIndexButton.html.html}} + + + + + + \ No newline at end of file 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