add email for verification with duration in text (for example: you have registered for 10 days),

This commit is contained in:
Dario 2020-06-15 17:23:44 +02:00
parent 5f9ec065af
commit 1573b1f70c
10 changed files with 217 additions and 26 deletions

View File

@ -101,4 +101,6 @@ namespace controller {
link += std::to_string(getModel()->getCode());
return link;
}
}

View File

@ -24,6 +24,7 @@ namespace controller {
inline Poco::AutoPtr<model::table::EmailOptIn> getModel() { return _getModel<model::table::EmailOptIn>(); }
std::string getLink();
inline Poco::Timespan getAge() { return Poco::DateTime() - getModel()->getCreated(); }
protected:
EmailVerificationCode(model::table::EmailOptIn* dbModel);

View File

@ -2,6 +2,7 @@
#include <stdexcept>
#include "sodium.h"
#include <assert.h>
// needed for memset in linux
#include <string.h>
@ -169,4 +170,35 @@ namespace DataTypeConverter
mm->releaseMemory(hex);
return hexString;
}
std::string convertTimespanToLocalizedString(Poco::Timespan duration, LanguageCatalog* lang)
{
assert(lang);
int value = 0;
std::string result;
std::string unit_name;
if (duration.days() > 0) {
value = duration.days();
unit_name = "Day";
}
else if (duration.hours() > 0) {
value = duration.hours();
unit_name = "Hour";
}
else if (duration.minutes() > 0) {
value = duration.minutes();
unit_name = "Minute";
}
else {
value = duration.seconds();
unit_name = "Second";
}
result = std::to_string(value);
result += " ";
std::string unit_plural = unit_name;
unit_plural += "s";
result += lang->ngettext(unit_name.data(), unit_plural.data(), value);
return result;
}
}

View File

@ -4,6 +4,9 @@
#include <string>
#include "../SingletonManager/MemoryManager.h"
#include "Poco/Timespan.h"
#include "../SingletonManager/LanguageManager.h"
namespace DataTypeConverter {
@ -27,6 +30,9 @@ namespace DataTypeConverter {
const char* numberParseStateToString(NumberParseState state);
//! \brief convert duration in string showing seconds, minutes, hours or days
std::string convertTimespanToLocalizedString(Poco::Timespan duration, LanguageCatalog* lang);
};
#endif // __GRADIDO_LOGIN_SERVER_LIB_DATA_TYPE_CONVERTER_H

View File

@ -5,6 +5,8 @@
#include "../TransactionBase.h"
#include "../lib/DataTypeConverter.h"
namespace model {
const static char EmailText_emailVerification[] = {u8"\
@ -18,6 +20,28 @@ Mit freundlichen Grüßen\n\
Dario, Gradido Server Admin\n\
"};
const static char EmailText_emailVerificationResend[] = { u8"\
Hallo [first_name] [last_name],\n\
\n\
Du oder jemand anderes hat sich vor 7 Tagen mit dieser E-Mail Adresse bei Gradido registriert.\n\
Wenn du es warst, klicke bitte auf den Link: [link]\n\
oder kopiere den obigen Link in Dein Browserfenster.\n\
\n\
Mit freundlichen Grüßen\n\
Dario, Gradido Server Admin\n\
" };
const static char EmailText_emailVerificationResendAfterLongTime[] = { u8"\
Hallo [first_name] [last_name],\n\
\n\
Du oder jemand anderes hat sich vor [duration] mit dieser E-Mail Adresse bei Gradido registriert.\n\
Wenn du es warst, klicke bitte auf den Link: [link] um dein Konto zu aktivieren\n\
oder kopiere den obigen Link in Dein Browserfenster.\n\
\n\
Mit freundlichen Grüßen\n\
Dario, Gradido Server Admin\n\
" };
const static char EmailText_emailVerificationOldElopageTransaction[] = { u8"\
Hallo [first_name] [last_name],\n\
\n\
@ -132,6 +156,7 @@ Gradido Login-Server\n\
mt.setParameter("charset", "utf-8");
const char* messageTemplate = nullptr;
std::string content_string;
switch (mType) {
case EMAIL_DEFAULT:
@ -147,6 +172,8 @@ Gradido Login-Server\n\
break;
case EMAIL_USER_VERIFICATION_CODE:
case EMAIL_USER_VERIFICATION_CODE_RESEND:
case EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME:
case EMAIL_USER_REGISTER_OLD_ELOPAGE:
case EMAIL_ADMIN_USER_VERIFICATION_CODE:
case EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND:
@ -162,7 +189,13 @@ Gradido Login-Server\n\
mailMessage->setSubject(langCatalog->gettext_str("Gradido: E-Mail Verification"));
messageTemplate = EmailText_emailVerification;
if (mType == EMAIL_ADMIN_USER_VERIFICATION_CODE) {
if (EMAIL_USER_VERIFICATION_CODE_RESEND == mType) {
messageTemplate = EmailText_emailVerificationResend;
}
else if (EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME == mType) {
messageTemplate = EmailText_emailVerificationResendAfterLongTime;
}
else if (mType == EMAIL_ADMIN_USER_VERIFICATION_CODE) {
messageTemplate = EmailText_adminEmailVerification;
}
else if (mType == EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND) {
@ -172,14 +205,17 @@ Gradido Login-Server\n\
messageTemplate = EmailText_emailVerificationOldElopageTransaction;
}
mailMessage->addContent(
new Poco::Net::StringPartSource(replaceUserNamesAndLink(
langCatalog->gettext(messageTemplate),
userTableModel->getFirstName(),
userTableModel->getLastName(),
mEmailVerificationCode->getLink()
), mt.toString())
content_string = replaceUserNamesAndLink(
langCatalog->gettext(messageTemplate),
userTableModel->getFirstName(),
userTableModel->getLastName(),
mEmailVerificationCode->getLink()
);
if (EMAIL_USER_VERIFICATION_CODE_RESEND_AFTER_LONG_TIME == mType) {
content_string = replaceDuration(content_string, mEmailVerificationCode->getAge(), langCatalog);
}
mailMessage->addContent(new Poco::Net::StringPartSource(content_string, mt.toString()));
break;
case EMAIL_USER_RESET_PASSWORD:
if (userTableModel.isNull() || mUser->getModel()->getEmail() == "") {
@ -292,6 +328,19 @@ Gradido Login-Server\n\
return result;
}
std::string Email::replaceDuration(std::string src, Poco::Timespan duration, LanguageCatalog* lang)
{
static const char* functionName = "Email::replaceDuration";
int findPos = src.find("[duration]");
if (findPos != src.npos) {
src.replace(findPos, 10, DataTypeConverter::convertTimespanToLocalizedString(duration, lang));
}
else {
addError(new Error(functionName, "no duration placeholder found"));
}
return src;
}
EmailType Email::convertTypeFromInt(int type)
{
if (type >= (int)EMAIL_MAX || type <= 0) {

View File

@ -24,17 +24,19 @@ namespace model {
enum EmailType
{
EMAIL_DEFAULT = 1,
EMAIL_ERROR = 2,
EMAIL_USER_VERIFICATION_CODE = 3,
EMAIL_ADMIN_USER_VERIFICATION_CODE = 4,
EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND = 5,
EMAIL_USER_RESET_PASSWORD = 6,
EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE = 7,
EMAIL_NOTIFICATION_TRANSACTION_CREATION = 8,
EMAIL_NOTIFICATION_TRANSACTION_TRANSFER = 9,
EMAIL_USER_REGISTER_OLD_ELOPAGE = 10,
EMAIL_MAX = 11
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
};
class Email: public ErrorList
@ -57,6 +59,7 @@ namespace model {
std::string replaceUserNamesAndLink(const char* src, const std::string& first_name, const std::string& last_name, const std::string& link);
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);
AutoPtr<controller::EmailVerificationCode> mEmailVerificationCode;
AutoPtr<controller::User> mUser;

View File

@ -25,7 +25,7 @@ namespace model {
}
EmailOptIn::EmailOptIn(const EmailOptInTuple& tuple)
: ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mEmailVerificationCode(tuple.get<2>()), mType(tuple.get<3>()), mResendCount(tuple.get<4>())
: ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mEmailVerificationCode(tuple.get<2>()), mType(tuple.get<3>()), mCreated(tuple.get<4>()), mResendCount(tuple.get<5>())
{
}
@ -53,9 +53,9 @@ namespace model {
{
Poco::Data::Statement select(session);
select << "SELECT id, user_id, verification_code, email_opt_in_type_id, resend_count FROM " << getTableName()
select << "SELECT id, user_id, verification_code, email_opt_in_type_id, created, resend_count FROM " << getTableName()
<< " where " << fieldName << " = ?"
, into(mID), into(mUserId), into(mEmailVerificationCode), into(mType), into(mResendCount);
, into(mID), into(mUserId), into(mEmailVerificationCode), into(mType), into(mCreated), into(mResendCount);
return select;
@ -76,7 +76,7 @@ namespace model {
{
Poco::Data::Statement select(session);
select << "SELECT id, user_id, verification_code, email_opt_in_type_id, resend_count FROM " << getTableName()
select << "SELECT id, user_id, verification_code, email_opt_in_type_id, created, resend_count FROM " << getTableName()
<< " where " << fieldName << " = ?";
@ -90,7 +90,7 @@ namespace model {
throw Poco::NullValueException("EmailOptIn::_loadFromDB fieldNames empty or contain only one field");
}
select << "SELECT user_id, verification_code, email_opt_in_type_id, resend_count FROM " << getTableName()
select << "SELECT user_id, verification_code, email_opt_in_type_id, created, resend_count FROM " << getTableName()
<< " where " << fieldNames[0] << " = ? ";
if (conditionType == MYSQL_CONDITION_AND) {
for (int i = 1; i < fieldNames.size(); i++) {
@ -106,7 +106,7 @@ namespace model {
addError(new ParamError("EmailOptIn::_loadFromDB", "condition type not implemented", conditionType));
}
//<< " where " << fieldName << " = ?"
select , into(mUserId), into(mEmailVerificationCode), into(mType), into(mResendCount);
select , into(mUserId), into(mEmailVerificationCode), into(mType), into(mCreated), into(mResendCount);
return select;

View File

@ -17,7 +17,7 @@ namespace model {
EMAIL_OPT_IN_REGISTER_DIRECT = 3
};
typedef Poco::Tuple<int, int, Poco::UInt64, int, int> EmailOptInTuple;
typedef Poco::Tuple<int, int, Poco::UInt64, int, Poco::DateTime, int> EmailOptInTuple;
class EmailOptIn : public ModelBase
{
@ -35,6 +35,7 @@ namespace model {
inline Poco::UInt64 getCode() const { return mEmailVerificationCode; }
inline int getUserId() const { return mUserId; }
inline int getResendCount() const { Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex); return mResendCount; }
inline Poco::DateTime getCreated() const { return mCreated; }
inline EmailOptInType getType() const { return static_cast<EmailOptInType>(mType);}
inline void setCode(Poco::UInt64 code) { mEmailVerificationCode = code; }
inline void setUserId(int user_Id) { mUserId = user_Id; }
@ -53,6 +54,7 @@ namespace model {
// data type must be a multiple of 4
Poco::UInt64 mEmailVerificationCode;
int mType;
Poco::DateTime mCreated;
int mResendCount;
};

View File

@ -0,0 +1,59 @@
#include "VerificationEmailResendTask.h"
#include "../controller/User.h"
#include "../controller/EmailVerificationCode.h"
#include "../SingletonManager/EmailManager.h"
VerificationEmailResendTask::VerificationEmailResendTask(int userId)
: mUserId(userId)
{
}
VerificationEmailResendTask::~VerificationEmailResendTask()
{
}
int VerificationEmailResendTask::run()
{
auto user = controller::User::create();
if (1 == user->load(mUserId)) {
auto model = user->getModel();
// if email is checked, we can exit
if (model->isEmailChecked()) {
return 1;
}
auto email_verification = controller::EmailVerificationCode::load(mUserId, model::table::EMAIL_OPT_IN_REGISTER_DIRECT);
if (nullptr == email_verification) {
email_verification = controller::EmailVerificationCode::create(mUserId, model::table::EMAIL_OPT_IN_REGISTER_DIRECT);
email_verification->getModel()->insertIntoDB(false);
}
auto em = EmailManager::getInstance();
em->addEmail(new model::Email(email_verification, user, model::EMAIL_USER_VERIFICATION_CODE_RESEND));
email_verification->getModel()->addResendCountAndUpdate();
}
return 0;
}
VerificationEmailResendTimerTask::VerificationEmailResendTimerTask(int userId)
: mUserId(userId)
{
}
VerificationEmailResendTimerTask::~VerificationEmailResendTimerTask()
{
}
void VerificationEmailResendTimerTask::run()
{
UniLib::controller::TaskPtr verificationResendTask(new VerificationEmailResendTask(mUserId));
verificationResendTask->scheduleTask(verificationResendTask);
}

View File

@ -0,0 +1,37 @@
#ifndef __GRADIDO_LOGIN_SERVER_VERIFICATION_EMAIL_RESEND_TIMER_TASK__H
#define __GRADIDO_LOGIN_SERVER_VERIFICATION_EMAIL_RESEND_TIMER_TASK__H
#include "CPUTask.h"
#include "Poco/Util/TimerTask.h"
class VerificationEmailResendTask : public UniLib::controller::CPUTask
{
public:
VerificationEmailResendTask(int userId);
~VerificationEmailResendTask();
const char* getResourceType() const { return "VerificationEmailResendTask"; };
//! from Poco::Util::TimerTask, called from timer if the time is there
//! load user from db, check if account is activated if not, send the email verification code a second time
int run();
protected:
int mUserId;
};
class VerificationEmailResendTimerTask : public Poco::Util::TimerTask
{
public:
VerificationEmailResendTimerTask(int userId);
~VerificationEmailResendTimerTask();
void run();
protected:
int mUserId;
};
#endif //__GRADIDO_LOGIN_SERVER_VERIFICATION_EMAIL_RESEND_TIMER_TASK__H