diff --git a/docu/login_server.api.md b/docu/login_server.api.md index 6690abc7f..51e29db96 100644 --- a/docu/login_server.api.md +++ b/docu/login_server.api.md @@ -98,6 +98,7 @@ Update password can only be used if in Login-Server config: ```ini unsecure.allow_passwort_via_json_request = 1 ``` +is set POST http://localhost/login_api/updateUserInfos ```json @@ -207,6 +208,65 @@ return - registerDirect: code generated by register for check email - register: code generated by auto-register via elopage for check email - info can contain additional info strings - - user hasn't password: if user hasn't set a password yet (for example if he was registered via elopage) - - email already activated: if email was already checked -- session_id: session_id for new session \ No newline at end of file + - "user hasn't password": if user hasn't set a password yet (for example if he was registered via elopage) + - "email already activated": if email was already checked +- session_id: session_id for new session + +## Send Emails +Let send Login-Server Password reset E-Mail to User +Can be also used for admin interface to resend email verification code +POST http://localhost/login_api/sendEmail +```json +{"email": "max.musterman@gmail.de", "email_text":7, "email_verification_code_type":"resetPassword" } +``` +also valid: +```json +{"email": "max.musterman@gmail.de", "email_text":"user reset Password", "email_verification_code_type":"resetPassword" } +``` +or: +```json +{"session_id": -127182, "email": "max.musterman@gmail.de", "email_text":5, "email_verification_code_type":"register" } +``` + +- session_id: not needed for resetPassword emails +- email_type: choose which email text should be used (number or string can be used) + - "email user verification code" (2): default text used when new user has registered + - "email user verification code resend" (3): text used when user hasn't activated his account 7 days after register + - "email user verification code resend after long time" (4): text used when user hasn't activated his account more than 7 days after register + - "email admin user verification code" (5): used if admin trigger sending the email with email verification code + - "email admin user verification code resend" (6): used if admin trigger sending the email with email verification code again + - "user reset Password" (7): used for reset password email text + - "email custom tex" (8): used if custom email text should be used (than email_custom_text must also be filled) +- email_verification_code_type + - resetPassword: for password resets, will be deleted immediately, is a only one use code, can be used without session_id + - registerDirect: code generated by register for check email, can only be used by admins for another user + - register: code generated by auto-register via elopage for check email, can only be used by admins for another user +- email_custom_text (optional): can be used to send email with custom text + placeholder for email text, will be replaced + - [first_name] first name + - [last_name] last name + - [duration] time span since user has created account (ex.: 10 Days) with largest unit, day is last unit + - [link] login-server checkEmail link with email verification code (ex.: http://localhost/account/checkEmail/382738273892983) + - [code] email verification code if you like to use your one link +- emailCustomSubject: for custom email the subject + +return +```json +{"state":"success"} +``` +if everything is okay +return +```json +{"state":"warning", "msg":"email already sended"} +``` +if emails was successfully sended but was already sended in past also. + +return with "state":"error" and additional "msg" if error occured (no email sended): +- "email already send less than a hour before": User has already get a password reset email and haven't used the link yet +- "not supported email type": with "email_verification_code_type":"resetPassword" only email type 7 or 8 allowed +- "admin needed": only admins can send email verification emails because this emails normally sended out automaticly +- "invalid email": if email wasn't found in db +- "invalid session": if session wasn't found (only checked if session_id is set and != 0) +- "invalid email type": could not parse email type +- "invalid verification code type": could not parse email verification code type +- "json exception": error parsing input json, more infos can be found in details \ No newline at end of file diff --git a/frontend/src/apis/loginAPI.js b/frontend/src/apis/loginAPI.js index 8756a6840..b9e433730 100644 --- a/frontend/src/apis/loginAPI.js +++ b/frontend/src/apis/loginAPI.js @@ -7,12 +7,31 @@ const EMAIL_TYPE = { ADMIN: 5, // if user was registered by an admin } +const apiGet = async (url) => { + try { + const result = await axios.get(url); + if(result.status !== 200){ + throw new Error('HTTP Status Error '+result.status) + } + + if(result.data.state !== 'success'){ + throw new Error(result.data.msg) + } + return { success: true, result } + } catch(error){ + return { success: false, result: error} + } +} + const apiPost = async (url, payload) => { try { const result = await axios.post(url, payload); if(result.status !== 200){ throw new Error('HTTP Status Error '+result.status) } + if(result.data.state === 'warning') { + return { success: true, result: error } + } if(result.data.state !== 'success'){ throw new Error(result.data.msg) } diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp b/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp index b66cba495..c8ca8964e 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandler.cpp @@ -139,3 +139,14 @@ Poco::JSON::Object* JsonRequestHandler::customStateError(const char* state, cons return result; } +Poco::JSON::Object* JsonRequestHandler::stateWarning(const char* msg, std::string details/* = ""*/) +{ + Poco::JSON::Object* result = new Poco::JSON::Object; + result->set("state", "warning"); + result->set("msg", msg); + if (details != "") { + result->set("details", details); + } + return result; +} + diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandler.h b/login_server/src/cpp/JSONInterface/JsonRequestHandler.h index 72230bfe4..998c48edf 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandler.h +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandler.h @@ -22,6 +22,7 @@ protected: static Poco::JSON::Object* stateError(const char* msg, std::string details = ""); static Poco::JSON::Object* customStateError(const char* state, const char* msg, std::string details = ""); static Poco::JSON::Object* stateSuccess(); + static Poco::JSON::Object* stateWarning(const char* msg, std::string details = ""); }; diff --git a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp index 5db715db3..2edb3d8b1 100644 --- a/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp +++ b/login_server/src/cpp/JSONInterface/JsonRequestHandlerFactory.cpp @@ -11,11 +11,13 @@ #include "JsonGetRunningUserTasks.h" #include "JsonGetUsers.h" #include "JsonLoginViaEmailVerificationCode.h" +#include "JsonLogout.h" +#include "JsonSendEmail.h" #include "JsonAdminEmailVerificationResend.h" #include "JsonGetUserInfos.h" #include "JsonUpdateUserInfos.h" #include "JsonUnsecureLogin.h" -#include "JsonLogout.h" + JsonRequestHandlerFactory::JsonRequestHandlerFactory() : mRemoveGETParameters("^/([a-zA-Z0-9_-]*)"), mLogging(Poco::Logger::get("requestLog")) @@ -71,6 +73,9 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c else if (url_first_part == "/loginViaEmailVerificationCode") { return new JsonLoginViaEmailVerificationCode(client_host); } + else if (url_first_part == "/sendEmail") { + return new JsonSendEmail; + } else if (url_first_part == "/logout") { return new JsonLogout(client_host); } diff --git a/login_server/src/cpp/JSONInterface/JsonSendEmail.cpp b/login_server/src/cpp/JSONInterface/JsonSendEmail.cpp new file mode 100644 index 000000000..f4525b3d7 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonSendEmail.cpp @@ -0,0 +1,149 @@ +#include "JsonSendEmail.h" + +#include "Poco/URI.h" + +#include "../SingletonManager/SessionManager.h" +#include "../SingletonManager/EmailManager.h" +#include "../SingletonManager/LanguageManager.h" + +#include "../controller/User.h" +#include "../controller/EmailVerificationCode.h" + +#include "../lib/DataTypeConverter.h" + +Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params) +{ + int session_id = 0; + std::string email; + model::EmailType emailType = model::EMAIL_DEFAULT; + model::table::EmailOptInType emailVerificationCodeType; + std::string emailCustomText; + std::string emailCustomSubject; + std::string languageCode; + + std::string email_verification_code_type_string; + std::string email_type_string; + int email_type_int = 0; + + // if is json object + if (params.type() == typeid(Poco::JSON::Object::Ptr)) { + Poco::JSON::Object::Ptr paramJsonObject = params.extract(); + /// Throws a RangeException if the value does not fit + /// into the result variable. + /// Throws a NotImplementedException if conversion is + /// not available for the given type. + /// Throws InvalidAccessException if Var is empty. + try { + + if (paramJsonObject->has("session_id")) { + paramJsonObject->get("session_id").convert(session_id); + } + + if (paramJsonObject->has("email_custom_text")) { + paramJsonObject->get("email_custom_text").convert(emailCustomText); + } + if (paramJsonObject->has("emailCustomSubject")) { + paramJsonObject->get("emailCustomSubject").convert(emailCustomSubject); + } + if (paramJsonObject->has("language")) { + paramJsonObject->get("language").convert(languageCode); + } + paramJsonObject->get("email").convert(email); + + paramJsonObject->get("email_verification_code_type").convert(email_verification_code_type_string); + auto email_text = paramJsonObject->get("email_text"); + if (email_text.isString()) { + email_text.convert(email_type_string); + } + else if (email_text.isInteger()) { + email_text.convert(email_type_int); + } + + } + catch (Poco::Exception& ex) { + return stateError("json exception", ex.displayText()); + } + } + // convert types into enum + if (email_type_int > 0 && email_type_int < model::EMAIL_MAX) { + emailType = (model::EmailType)email_type_int; + } + else if (email_type_string != "") { + emailType = model::Email::emailType(email_type_string); + } + emailVerificationCodeType = model::table::EmailOptIn::stringToType(email_verification_code_type_string); + if (model::table::EMAIL_OPT_IN_EMPTY == emailVerificationCodeType) { + return stateError("invalid verification code type"); + } + + switch (emailType) { + case model::EMAIL_DEFAULT: + case model::EMAIL_ERROR: + case model::EMAIL_MAX: return stateError("invalid email type"); + } + + if (0 == session_id && + (model::table::EMAIL_OPT_IN_REGISTER == emailVerificationCodeType || model::table::EMAIL_OPT_IN_REGISTER_DIRECT == emailVerificationCodeType) + ){ + return stateError("login needed"); + } + + auto sm = SessionManager::getInstance(); + auto em = EmailManager::getInstance(); + auto lm = LanguageManager::getInstance(); + + Session* session = nullptr; + if (session_id != 0) { + session = sm->getSession(session_id); + if (nullptr == session) { + return stateError("invalid session"); + } + } + + auto receiver_user = controller::User::create(); + if (1 != receiver_user->load(email)) { + return stateError("invalid email"); + } + auto receiver_user_id = receiver_user->getModel()->getID(); + + if (emailVerificationCodeType == model::table::EMAIL_OPT_IN_RESET_PASSWORD) + { + session = sm->getNewSession(); + if (emailType == model::EMAIL_USER_RESET_PASSWORD) { + auto r = session->sendResetPasswordEmail(receiver_user, false); + if (1 == r) { + return stateWarning("email already sended"); + } + else if (2 == r) { + return stateError("email already send less than a hour before"); + } + } + else if (emailType == model::EMAIL_CUSTOM_TEXT) { + auto email_verification_code_object = controller::EmailVerificationCode::loadOrCreate(receiver_user_id, model::table::EMAIL_OPT_IN_RESET_PASSWORD); + auto email = new model::Email(email_verification_code_object, receiver_user, emailCustomText, emailCustomSubject); + em->addEmail(email); + } + else { + return stateError("not supported email type"); + } + return stateSuccess(); + } + else + { + if (session->getNewUser()->getModel()->getRole() != model::table::ROLE_ADMIN) { + return stateError("admin needed"); + } + + auto email_verification_code_object = controller::EmailVerificationCode::loadOrCreate(receiver_user_id, emailVerificationCodeType); + model::Email* email = nullptr; + if (emailType == model::EMAIL_CUSTOM_TEXT) { + email = new model::Email(email_verification_code_object, receiver_user, emailCustomText, emailCustomSubject); + } + else { + email = new model::Email(email_verification_code_object, receiver_user, emailType); + } + em->addEmail(email); + return stateSuccess(); + } + +} \ No newline at end of file diff --git a/login_server/src/cpp/JSONInterface/JsonSendEmail.h b/login_server/src/cpp/JSONInterface/JsonSendEmail.h new file mode 100644 index 000000000..e1c7d6904 --- /dev/null +++ b/login_server/src/cpp/JSONInterface/JsonSendEmail.h @@ -0,0 +1,16 @@ +#ifndef __JSON_SEND_EMAIL_H +#define __JSON_SEND_EMAIL_H + +#include "JsonRequestHandler.h" + +class JsonSendEmail : public JsonRequestHandler +{ +public: + Poco::JSON::Object* handle(Poco::Dynamic::Var params); + +protected: + + +}; + +#endif // __JSON_SEND_EMAIL_H \ No newline at end of file diff --git a/login_server/src/cpp/controller/EmailVerificationCode.cpp b/login_server/src/cpp/controller/EmailVerificationCode.cpp index e144d57eb..375d80f06 100644 --- a/login_server/src/cpp/controller/EmailVerificationCode.cpp +++ b/login_server/src/cpp/controller/EmailVerificationCode.cpp @@ -67,6 +67,24 @@ namespace controller { return nullptr; } + Poco::AutoPtr EmailVerificationCode::loadOrCreate(int user_id, model::table::EmailOptInType type) + { + model::table::EmailOptIn db; + std::vector fields = { "user_id", "email_opt_in_type_id" }; + std::vector field_values = { user_id, (int)type }; + auto results = db.loadFromDB(fields, field_values); + if (results.size() > 0) { + return Poco::AutoPtr(new EmailVerificationCode(new model::table::EmailOptIn(results[0]))); + } + else { + auto result = create(user_id, type); + result->getModel()->insertIntoDB(false); + return result; + } + + return nullptr; + } + std::vector> EmailVerificationCode::load(int user_id) { auto db = new model::table::EmailOptIn(); diff --git a/login_server/src/cpp/controller/EmailVerificationCode.h b/login_server/src/cpp/controller/EmailVerificationCode.h index 77d607de3..825bbc823 100644 --- a/login_server/src/cpp/controller/EmailVerificationCode.h +++ b/login_server/src/cpp/controller/EmailVerificationCode.h @@ -14,6 +14,8 @@ namespace controller { static Poco::AutoPtr create(int user_id, model::table::EmailOptInType type = model::table::EMAIL_OPT_IN_REGISTER); static Poco::AutoPtr create(model::table::EmailOptInType type = model::table::EMAIL_OPT_IN_REGISTER); + //! try to load code, create if not exist and save into db + static Poco::AutoPtr loadOrCreate(int user_id, model::table::EmailOptInType type); static Poco::AutoPtr load(const Poco::UInt64& code); static std::vector> load(int user_id); diff --git a/login_server/src/cpp/model/email/Email.cpp b/login_server/src/cpp/model/email/Email.cpp index 2efa473e4..e70d19729 100644 --- a/login_server/src/cpp/model/email/Email.cpp +++ b/login_server/src/cpp/model/email/Email.cpp @@ -130,6 +130,16 @@ Gradido Login-Server\n\ : mUser(user), mType(type) { + } + Email::Email( + AutoPtr emailVerification, + AutoPtr user, + const std::string& emailCustomText, + const std::string& customSubject + ) + : mEmailVerificationCode(emailVerification), mUser(user), mType(EMAIL_CUSTOM_TEXT), mCustomText(emailCustomText), mCustomSubject(customSubject) + { + } Email::~Email() @@ -177,6 +187,7 @@ Gradido Login-Server\n\ case EMAIL_USER_REGISTER_OLD_ELOPAGE: case EMAIL_ADMIN_USER_VERIFICATION_CODE: case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND: + case EMAIL_CUSTOM_TEXT: if (userTableModel.isNull() || mUser->getModel()->getEmail() == "") { addError(new Error(functionName, "no receiver email set for user email verification email")); return false; @@ -204,14 +215,19 @@ Gradido Login-Server\n\ else if (mType == EMAIL_USER_REGISTER_OLD_ELOPAGE) { messageTemplate = EmailText_emailVerificationOldElopageTransaction; } + else if (mType == EMAIL_CUSTOM_TEXT) { + messageTemplate = mCustomText.data(); + mailMessage->setSubject(mCustomSubject); + } content_string = replaceUserNamesAndLink( langCatalog->gettext(messageTemplate), userTableModel->getFirstName(), userTableModel->getLastName(), - mEmailVerificationCode->getLink() + mEmailVerificationCode->getLink(), + mEmailVerificationCode->getModel()->getCode() ); - if (EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME == mType) { + if (EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME == mType || EMAIL_CUSTOM_TEXT == mType) { content_string = replaceDuration(content_string, mEmailVerificationCode->getAge(), langCatalog); } mailMessage->addContent(new Poco::Net::StringPartSource(content_string, mt.toString())); @@ -234,7 +250,8 @@ Gradido Login-Server\n\ langCatalog->gettext(EmailText_emailResetPassword), userTableModel->getFirstName(), userTableModel->getLastName(), - mEmailVerificationCode->getLink() + mEmailVerificationCode->getLink(), + mEmailVerificationCode->getModel()->getCode() ), mt.toString()) ); break; @@ -264,8 +281,13 @@ Gradido Login-Server\n\ return true; } - std::string Email::replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link) - { + std::string Email::replaceUserNamesAndLink( + const char* src, + const std::string& first_name, + const std::string& last_name, + const std::string& link, + Poco::UInt64 code + ) { std::string result = src; int findCursor = 0; static const char* functionName = "Email::replaceUserNamesAndLink"; @@ -296,6 +318,12 @@ Gradido Login-Server\n\ else { //addError(new Error(functionName, "no email placeholder found")); } + findPos = result.find("[code]", findCursor); + if (findPos != result.npos) { + auto code_string = std::to_string(code); + findCursor = findPos + code_string.size(); + result.replace(findPos, 6, code_string); + } return result; } @@ -376,12 +404,38 @@ Gradido Login-Server\n\ case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND: return "email admin user verification code resend"; case EMAIL_USER_RESET_PASSWORD: return "user reset Password"; case EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE: return "user reset password without memorized passphrase"; - case EMAIL_NOTIFICATION_TRANSACTION_CREATION: return "email notification transaction creation"; - case EMAIL_NOTIFICATION_TRANSACTION_TRANSFER: return "email notification transaction transfer"; case EMAIL_USER_REGISTER_OLD_ELOPAGE: return "user register automatic throw elopage"; + case EMAIL_CUSTOM_TEXT: return "email custom text"; case EMAIL_MAX: return ""; } return ""; } + EmailType Email::emailType(const std::string& emailTypeString) + { + if ("email user verification code" == emailTypeString) { + return EMAIL_USER_VERIFICATION_CODE; + } + else if ("email user verification code resend" == emailTypeString) { + return EMAIL_USER_VERIFICATION_CODE_RESEND; + } + else if ("email user verification code resend after long time" == emailTypeString) { + return EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME; + } + else if ("email admin user verification code") { + return EMAIL_ADMIN_USER_VERIFICATION_CODE; + } + else if ("email admin user verification code resend") { + return EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND; + } + else if ("user reset Password") { + return EMAIL_USER_RESET_PASSWORD; + } + else if ("email custom text") { + return EMAIL_CUSTOM_TEXT; + } + else { + return EMAIL_ERROR; + } + } } \ No newline at end of file diff --git a/login_server/src/cpp/model/email/Email.h b/login_server/src/cpp/model/email/Email.h index d2887a26c..9dbfb1f07 100644 --- a/login_server/src/cpp/model/email/Email.h +++ b/login_server/src/cpp/model/email/Email.h @@ -22,21 +22,20 @@ namespace model { using namespace Poco; - enum EmailType + enum EmailType { - EMAIL_DEFAULT, - EMAIL_ERROR, - EMAIL_USER_VERIFICATION_CODE, - EMAIL_USER_VERIFICATION_CODE_RESEND, - EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME, - EMAIL_ADMIN_USER_VERIFICATION_CODE, - EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND, - EMAIL_USER_RESET_PASSWORD, - EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE, - EMAIL_NOTIFICATION_TRANSACTION_CREATION, - EMAIL_NOTIFICATION_TRANSACTION_TRANSFER, - EMAIL_USER_REGISTER_OLD_ELOPAGE, - EMAIL_MAX + EMAIL_DEFAULT = 0, + EMAIL_ERROR = 1, + EMAIL_USER_VERIFICATION_CODE = 2, + EMAIL_USER_VERIFICATION_CODE_RESEND = 3, + EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME = 4, + EMAIL_ADMIN_USER_VERIFICATION_CODE = 5, + EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND = 6, + EMAIL_USER_RESET_PASSWORD = 7, + EMAIL_CUSTOM_TEXT = 8, + EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE = 9, + EMAIL_USER_REGISTER_OLD_ELOPAGE = 10, + EMAIL_MAX = 11 }; class Email: public ErrorList @@ -44,6 +43,7 @@ namespace model { public: Email(AutoPtr emailVerification, AutoPtr user, EmailType type); Email(AutoPtr user, EmailType type); + Email(AutoPtr emailVerification, AutoPtr user, const std::string& emailCustomText, const std::string& customSubject); //! \param errors copy errors into own memory Email(const std::string& errorHtml, EmailType type); ~Email(); @@ -51,6 +51,7 @@ namespace model { static EmailType convertTypeFromInt(int type); inline EmailType getType() { return mType; } static const char* emailTypeString(EmailType type); + static EmailType emailType(const std::string& emailTypeString); inline controller::User* getUser() { if (!mUser.isNull()) return mUser.get(); return nullptr; } virtual bool draft(Net::MailMessage* mailMessage, LanguageCatalog* langCatalog); @@ -58,7 +59,7 @@ namespace model { protected: - std::string replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link); + std::string replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link, Poco::UInt64 code); std::string replaceEmail(const char* src, const std::string& email); std::string replaceAmount(const char* src, Poco::Int64 gradido_cent); std::string replaceDuration(std::string src, Poco::Timespan duration, LanguageCatalog* lang); @@ -69,6 +70,8 @@ namespace model { EmailType mType; std::queue mAdditionalStringPartSrcs; + std::string mCustomText; + std::string mCustomSubject; }; } diff --git a/login_server/src/cpp/model/table/EmailOptIn.cpp b/login_server/src/cpp/model/table/EmailOptIn.cpp index 09a75ee29..3e89516e8 100644 --- a/login_server/src/cpp/model/table/EmailOptIn.cpp +++ b/login_server/src/cpp/model/table/EmailOptIn.cpp @@ -172,6 +172,19 @@ namespace model { default: return ""; } } + EmailOptInType EmailOptIn::stringToType(const std::string& typeString) + { + if (typeString == "register") { + return EMAIL_OPT_IN_REGISTER; + } + else if (typeString == "resetPassword") { + return EMAIL_OPT_IN_RESET_PASSWORD; + } + else if (typeString == "registerDirect") { + return EMAIL_OPT_IN_REGISTER_DIRECT; + } + return EMAIL_OPT_IN_EMPTY; + } } } diff --git a/login_server/src/cpp/model/table/EmailOptIn.h b/login_server/src/cpp/model/table/EmailOptIn.h index 913c84aa1..c7a21d84c 100644 --- a/login_server/src/cpp/model/table/EmailOptIn.h +++ b/login_server/src/cpp/model/table/EmailOptIn.h @@ -44,6 +44,7 @@ namespace model { size_t addResendCountAndUpdate(); static const char* typeToString(EmailOptInType type); + static EmailOptInType stringToType(const std::string& typeString); protected: Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session);