filter elopage products, save elopage buys

This commit is contained in:
Dario 2019-10-31 11:15:34 +01:00
parent 0181d8fef6
commit 0c00a3e809
10 changed files with 285 additions and 77 deletions

View File

@ -16,6 +16,7 @@ using namespace Poco::Data::Keywords;
#include "../tasks/SendEmailTask.h"
#include "../model/EmailVerificationCode.h"
#include "../model/ElopageBuy.h"
@ -100,6 +101,8 @@ void ElopageWebhook::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::
if (event == "lesson.viewed") {
return;
}
// write stream result also to file
static Poco::Mutex mutex;
@ -175,6 +178,7 @@ void HandleElopageRequestTask::writeUserIntoDB()
}
}
int HandleElopageRequestTask::getUserIdFromDB()
{
auto cm = ConnectionManager::getInstance();
@ -203,87 +207,118 @@ int HandleElopageRequestTask::run()
return 0;
}
mEmail = mRequestData.get("payer[email]", "");
mFirstName = mRequestData.get("payer[first_name]", "");
mLastName = mRequestData.get("payer[last_name]", "");
std::string order_id = mRequestData.get("order_id", "");
// elopage buy
Poco::AutoPtr<ElopageBuy> elopageBuy(new ElopageBuy(mRequestData));
if (elopageBuy->errorCount() > 0) {
getErrors(elopageBuy);
}
UniLib::controller::TaskPtr saveElopageBuy(new ModelInsertTask(elopageBuy));
saveElopageBuy->scheduleTask(saveElopageBuy);
// check product id
Poco::UInt64 product_id = 0;
try {
product_id = stoull(mRequestData.get("product[id]", "0"));
}
catch (const std::invalid_argument& ia) {
std::cerr << __FUNCTION__ << "Invalid argument: " << ia.what() << '\n';
}
catch (const std::out_of_range& oor) {
std::cerr << __FUNCTION__ << "Out of Range error: " << oor.what() << '\n';
}
catch (const std::logic_error & ler) {
std::cerr << __FUNCTION__ << "Logical error: " << ler.what() << '\n';
}
catch (...) {
std::cerr << __FUNCTION__ << "Unknown error" << '\n';
}
std::string order_id = mRequestData.get("order_id", "");
addError(new ParamError("HandleElopageRequestTask", "order_id", order_id.data()));
// validate input
if (!validateInput()) {
// if input is invalid we can stop now
sendErrorsAsEmail();
return -1;
// only for product 36001 and 43741 create user accounts and send emails
if (product_id == 36001 || product_id == 43741) {
mEmail = mRequestData.get("payer[email]", "");
mFirstName = mRequestData.get("payer[first_name]", "");
mLastName = mRequestData.get("payer[last_name]", "");
// validate input
if (!validateInput()) {
// if input is invalid we can stop now
sendErrorsAsEmail();
return -1;
}
// if user exist we can stop now
if (getUserIdFromDB()) {
sendErrorsAsEmail();
return -2;
}
// if user with this email didn't exist
// we can create a new user and send a email to him
// prepare email in advance
// create connection to email server
UniLib::controller::TaskPtr prepareEmail(new PrepareEmailTask(ServerConfig::g_CPUScheduler));
prepareEmail->scheduleTask(prepareEmail);
// write user entry into db
writeUserIntoDB();
// get user id from db
int user_id = getUserIdFromDB();
// we didn't get a user_id, something went wrong
if (!user_id) {
addError(new Error("User loadEntryDBId", "user_id is zero"));
sendErrorsAsEmail();
return -3;
}
// email verification code
Poco::AutoPtr<EmailVerificationCode> emailVerification(new EmailVerificationCode(user_id));
// create email verification code
if (!emailVerification->getCode()) {
// exit if email verification code is empty
addError(new Error("Email verification", "code is empty, error in random?"));
sendErrorsAsEmail();
return -4;
}
// write email verification code into db
UniLib::controller::TaskPtr saveEmailVerificationCode(new ModelInsertTask(emailVerification));
saveEmailVerificationCode->scheduleTask(saveEmailVerificationCode);
// send email to user
auto message = new Poco::Net::MailMessage;
message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, mEmail));
message->setSubject("Gradido: E-Mail Verification");
std::stringstream ss;
ss << "Hallo " << mFirstName << " " << mLastName << "," << std::endl << std::endl;
ss << "Du oder jemand anderes hat sich soeben mit dieser E-Mail Adresse bei Gradido registriert. " << std::endl;
ss << "Wenn du es warst, klicke bitte auf den Link: " << ServerConfig::g_serverPath << "/checkEmail/" << emailVerification->getCode() << std::endl;
//ss << "oder kopiere den Code: " << mEmailVerificationCode << " selbst dort hinein." << std::endl;
ss << "oder kopiere den obigen Link in Dein Browserfenster." << std::endl;
ss << std::endl;
ss << "Mit freundlichen Grüße" << std::endl;
ss << "Dario, Gradido Server Admin" << std::endl;
message->addContent(new Poco::Net::StringPartSource(ss.str()));
UniLib::controller::TaskPtr sendEmail(new SendEmailTask(message, ServerConfig::g_CPUScheduler, 1));
sendEmail->setParentTaskPtrInArray(prepareEmail, 0);
sendEmail->setParentTaskPtrInArray(saveEmailVerificationCode, 1);
sendEmail->scheduleTask(sendEmail);
}
// if user exist we can stop now
if (getUserIdFromDB()) {
sendErrorsAsEmail();
return -2;
}
// if user with this email didn't exist
// we can create a new user and send a email to him
// prepare email in advance
// create connection to email server
UniLib::controller::TaskPtr prepareEmail(new PrepareEmailTask(ServerConfig::g_CPUScheduler));
prepareEmail->scheduleTask(prepareEmail);
// write user entry into db
writeUserIntoDB();
// get user id from db
int user_id = getUserIdFromDB();
// we didn't get a user_id, something went wrong
if (!user_id) {
addError(new Error("User loadEntryDBId", "user_id is zero"));
sendErrorsAsEmail();
return -3;
}
Poco::AutoPtr<EmailVerificationCode> emailVerification(new EmailVerificationCode(user_id));
// create email verification code
if (!emailVerification->getCode()) {
// exit if email verification code is empty
addError(new Error("Email verification", "code is empty, error in random?"));
sendErrorsAsEmail();
return -4;
}
// write email verification code into db
UniLib::controller::TaskPtr saveEmailVerificationCode(new ModelInsertTask(emailVerification));
saveEmailVerificationCode->scheduleTask(saveEmailVerificationCode);
// send email to user
auto message = new Poco::Net::MailMessage;
message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, mEmail));
message->setSubject("Gradido: E-Mail Verification");
std::stringstream ss;
ss << "Hallo " << mFirstName << " " << mLastName << "," << std::endl << std::endl;
ss << "Du oder jemand anderes hat sich soeben mit dieser E-Mail Adresse bei Elopage für Gradido angemeldet. " << std::endl;
ss << "Um dein Gradido Konto anzulegen und deine E-Mail zu bestätigen," << std::endl;
ss << "klicke bitte auf den Link: https://gradido2.dario-rekowski.de/account/checkEmail/" << emailVerification->getCode() << std::endl;
ss << "oder kopiere den Code: " << emailVerification->getCode() << " selbst dort hinein." << std::endl << std::endl;
ss << "Mit freundlichen Grüße" << std::endl;
ss << "Dario, Gradido Server Admin" << std::endl;
message->addContent(new Poco::Net::StringPartSource(ss.str()));
UniLib::controller::TaskPtr sendEmail(new SendEmailTask(message, ServerConfig::g_CPUScheduler, 1));
sendEmail->setParentTaskPtrInArray(prepareEmail, 0);
sendEmail->setParentTaskPtrInArray(saveEmailVerificationCode, 1);
sendEmail->scheduleTask(sendEmail);
// if errors occured, send via email
//if (errorCount() > 1) {
if (errorCount() > 1) {
sendErrorsAsEmail();
//}
}
return 0;
}

View File

@ -179,15 +179,15 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi
auto str = uri.substr(pos + 1);
verificationCode = stoull(uri.substr(pos + 1));
} catch (const std::invalid_argument& ia) {
std::cerr << "Invalid argument: " << ia.what() << '\n';
std::cerr << __FUNCTION__ << "Invalid argument: " << ia.what() << '\n';
} catch (const std::out_of_range& oor) {
std::cerr << "Out of Range error: " << oor.what() << '\n';
std::cerr << __FUNCTION__ << "Out of Range error: " << oor.what() << '\n';
}
catch (const std::logic_error & ler) {
std::cerr << "Logical error: " << ler.what() << '\n';
std::cerr << __FUNCTION__ << "Logical error: " << ler.what() << '\n';
}
catch (...) {
std::cerr << "Unknown error" << '\n';
std::cerr << __FUNCTION__ << "Unknown error" << '\n';
}
}

View File

@ -2,6 +2,8 @@
#include "Poco/Mutex.h"
#include <time.h>
#include "../ServerConfig.h"
MysqlTable::MysqlTable(size_t fieldCount)
: mFieldCount(fieldCount), mHeader(nullptr)
{
@ -114,7 +116,7 @@ time_t MysqlTable::parseFromMysqlDateTime(const char* mysql_date_time)
struct tm * parsedTime;
// used because localtime return an internal pointer, not thread safe
static Poco::Mutex timeMutex;
Poco::Mutex& timeMutex = ServerConfig::g_TimeMutex;
int year, month, day, hour, minute, second;
// ex: 2009-10-29

View File

@ -39,6 +39,7 @@ namespace ServerConfig {
int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT;
std::string g_serverPath;
std::string g_php_serverPath;
Poco::Mutex g_TimeMutex;
bool loadMnemonicWordLists()
{

View File

@ -38,6 +38,7 @@ namespace ServerConfig {
extern int g_SessionTimeout;
extern std::string g_serverPath;
extern std::string g_php_serverPath;
extern Poco::Mutex g_TimeMutex;
bool loadMnemonicWordLists();

View File

@ -0,0 +1,76 @@
#include "ElopageBuy.h"
using namespace Poco::Data::Keywords;
const static std::string g_requestFieldsNames[] = {
"product[affiliate_program_id]", "publisher[id]", "order_id", "product_id",
"product[price]", "payer[email]", "payment_state", "success_date", "event" };
ElopageBuy::ElopageBuy(const Poco::Net::NameValueCollection& elopage_webhook_requestData)
: mPayed(false)
{
memset(mIDs, 0, ELOPAGE_BUY_MAX * sizeof(Poco::Int32));
for (int i = 0; i < 5; i++) {
std::string temp = elopage_webhook_requestData.get(g_requestFieldsNames[i], "0");
//printf("get: %s for field: %s (%d)\n", temp.data(), g_requestFieldsNames[i].data(), i);
try {
if (i == 4) {
mIDs[i+1] = static_cast<Poco::Int32>(round(stof(temp) * 100.0f));
}
else {
mIDs[i+1] = stoul(temp);
}
}
catch (const std::invalid_argument& ia) {addError(new ParamError("ElopageBuy", "parse string to number, invalid argument", ia.what()));}
catch (const std::out_of_range& oor) { addError(new ParamError("ElopageBuy", "parse string to number, Out of Range error", oor.what()));}
catch (const std::logic_error & ler) { addError(new ParamError("ElopageBuy", "parse string to number, Logical error", ler.what()));}
catch (...) {addError(new Error("ElopageBuy", "parse string to number, unknown error"));}
}
mPayerEmail = elopage_webhook_requestData.get(g_requestFieldsNames[5], "");
std::string payed = elopage_webhook_requestData.get(g_requestFieldsNames[6], "");
// payment_state = paid
if (payed == "paid") mPayed = true;
mSuccessDate = parseElopageDate(elopage_webhook_requestData.get(g_requestFieldsNames[7], ""));
mEvent = elopage_webhook_requestData.get(g_requestFieldsNames[8], "");
}
ElopageBuy::~ElopageBuy()
{
}
/*
ELOPAGE_BUY_AFFILIATE_PROGRAM_ID,
ELOPAGE_BUY_PUBLISHER_ID,
ELOPAGE_BUY_ORDER_ID,
ELOPAGE_BUY_PRODUCT_ID,
ELOPAGE_BUY_PRODUCT_PRICE
*/
Poco::Data::Statement ElopageBuy::insertIntoDB(Poco::Data::Session session)
{
Poco::Data::Statement insert(session);
lock();
insert << "INSERT INTO " << getTableName()
<< " (affiliate_program_id, publisher_id, order_id, product_id, product_price, payer_email, payed, success_date, event) "
<< " VALUES(?,?,?,?,?,?,?,?,?)"
, bind(mIDs[ELOPAGE_BUY_AFFILIATE_PROGRAM_ID]), bind(mIDs[ELOPAGE_BUY_PUBLISHER_ID])
, bind(mIDs[ELOPAGE_BUY_ORDER_ID]), bind(mIDs[ELOPAGE_BUY_PRODUCT_ID]), bind(mIDs[ELOPAGE_BUY_PRODUCT_PRICE])
, bind(mPayerEmail), bind(mPayed), bind(mSuccessDate), bind(mEvent);
unlock();
return insert;
}
Poco::Data::Statement ElopageBuy::updateIntoDB(Poco::Data::Session session)
{
throw Poco::Exception("ElopageBuy::updateIntoDB not implemented");
}
Poco::Data::Statement ElopageBuy::loadFromDB(Poco::Data::Session session, std::string& fieldName)
{
// Poco::Data::Statement select(session);
throw Poco::Exception("ElopageBuy::loadFromDB not implemented");
}

View File

@ -0,0 +1,51 @@
#ifndef GRADIDO_LOGIN_SERVER_MODEL_ELOPAGE_BUY_INCLUDE
#define GRADIDO_LOGIN_SERVER_MODEL_ELOPAGE_BUY_INCLUDE
/*!
* @author: Dario Rekowski
*
* @date: 31.10.2019
*
* @brief: Model for handling Elopage publisher
*
*/
#include "ModelBase.h"
#include "Poco/Types.h"
#include "Poco/Net/NameValueCollection.h"
enum ElopageBuyId {
ELOPAGE_BUY_ID,
ELOPAGE_BUY_AFFILIATE_PROGRAM_ID,
ELOPAGE_BUY_PUBLISHER_ID,
ELOPAGE_BUY_ORDER_ID,
ELOPAGE_BUY_PRODUCT_ID,
ELOPAGE_BUY_PRODUCT_PRICE,
ELOPAGE_BUY_MAX
};
class ElopageBuy : public ModelBase
{
public:
ElopageBuy(const Poco::Net::NameValueCollection& elopage_webhook_requestData);
~ElopageBuy();
// generic db operations
const char* getTableName() { return "elopage_buys"; }
Poco::Data::Statement insertIntoDB(Poco::Data::Session session);
Poco::Data::Statement updateIntoDB(Poco::Data::Session session);
Poco::Data::Statement loadFromDB(Poco::Data::Session session, std::string& fieldName);
protected:
Poco::Int32 mIDs[ELOPAGE_BUY_MAX];
std::string mPayerEmail;
bool mPayed;
Poco::DateTime mSuccessDate;
std::string mEvent;
};
#endif //GRADIDO_LOGIN_SERVER_MODEL_ELOPAGE_BUY_INCLUDE

View File

@ -1,9 +1,12 @@
#include "ModelBase.h"
#include "sodium.h"
#include "../ServerConfig.h"
#include "../SingletonManager/ConnectionManager.h"
#include "Poco/URI.h"
ModelInsertTask::ModelInsertTask(Poco::AutoPtr<ModelBase> model)
: UniLib::controller::CPUTask(ServerConfig::g_CPUScheduler), mModel(model)
{
@ -50,4 +53,41 @@ void ModelBase::release()
}
unlock();
}
Poco::DateTime ModelBase::parseElopageDate(std::string dateString)
{
std::string decodedDateString = "";
Poco::URI::decode(dateString, decodedDateString);
struct tm * parsedTime;
// used because localtime return an internal pointer, not thread safe
Poco::Mutex& timeMutex = ServerConfig::g_TimeMutex;
int year, month, day, hour, minute, second;
// ex: 2009-10-29
if (sscanf(decodedDateString.data(), "%d-%d-%dT%d:%dZ", &year, &month, &day, &hour, &minute) != EOF) {
time_t rawTime;
time(&rawTime);
// static, used for every thread
timeMutex.lock();
parsedTime = localtime(&rawTime);
// tm_year is years since 1900
parsedTime->tm_year = year - 1900;
// tm_months is months since january
parsedTime->tm_mon = month - 1;
parsedTime->tm_mday = day;
parsedTime->tm_hour = hour;
parsedTime->tm_min = minute;
parsedTime->tm_sec = 0;
rawTime = mktime(parsedTime);
timeMutex.unlock();
// rawTime is in seconds, poco timestamp in microseconds
return Poco::DateTime(Poco::Timestamp(rawTime* 1000000));
}
return Poco::DateTime(Poco::Timestamp());
}

View File

@ -25,6 +25,8 @@ public:
inline void setID(int id) { lock(); mID = id; unlock(); }
inline int getID() { lock(); int id = mID; unlock(); return id; }
static Poco::DateTime parseElopageDate(std::string dateString);
// for poco auto ptr
void duplicate();
void release();

View File

@ -50,7 +50,7 @@ label:not(.grd_radio_label) {
<body>
<div class="versionstring dev-info">
<p class="grd_small">Login Server in Entwicklung</p>
<p class="grd_small">Alpha 0.4.3</p>
<p class="grd_small">Alpha 0.4.4</p>
</div>
<!--<nav class="grd-left-bar expanded" data-topbar role="navigation">
<div class="grd-left-bar-section">