add create transaction to json interface, add functions for creating transfer and creation transaction on login server

This commit is contained in:
Dario 2020-10-27 17:28:07 +01:00 committed by Ulf Gebhardt
parent 813de3f053
commit 06b425a658
No known key found for this signature in database
GPG Key ID: 81308EFE29ABFEBD
24 changed files with 568 additions and 33 deletions

View File

@ -1,6 +1,7 @@
CREATE TABLE `pending_tasks` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int UNSIGNED DEFAULT '0',
`user_id` int UNSIGNED DEFAULT 0,
`hedera_id` int UNSIGNED DEFAULT 0,
`request` varbinary(2048) NOT NULL,
`created` datetime NOT NULL,
`finished` datetime DEFAULT '2000-01-01 000000',

View File

@ -3,6 +3,7 @@ CREATE TABLE `users` (
`email` varchar(191) NOT NULL,
`first_name` varchar(150) NOT NULL,
`last_name` varchar(255) DEFAULT '',
`username` varchar(255) DEFAULT '',
`password` bigint unsigned NOT NULL,
`pubkey` binary(32) DEFAULT NULL,
`privkey` binary(80) DEFAULT NULL,

View File

@ -0,0 +1,185 @@
#include "JsonCreateTransaction.h"
#include "../controller/User.h"
#include "../lib/DataTypeConverter.h"
#include "../model/gradido/Transaction.h"
Poco::JSON::Object* JsonCreateTransaction::handle(Poco::Dynamic::Var params)
{
auto sm = SessionManager::getInstance();
int session_id = 0;
std::string transaction_type;
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// 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 {
paramJsonObject->get("session_id").convert(session_id);
paramJsonObject->get("transaction_type").convert(transaction_type);
paramJsonObject->get("memo").convert(mMemo);
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
if (!session_id) {
return stateError("session_id invalid");
}
mSession = sm->getSession(session_id);
if (!mSession) {
return customStateError("not found", "session not found");
}
auto user = mSession->getNewUser();
if (user.isNull()) {
return customStateError("code error", "user is zero");
}
getTargetGroup(params);
if (transaction_type == "transfer") {
return transfer(params);
}
else if (transaction_type == "creation") {
return creation(params);
}
else if (transaction_type == "groupMemberUpdate") {
return groupMemberUpdate(params);
}
return stateError("transaction_type unknown");
}
Poco::JSON::Object* JsonCreateTransaction::transfer(Poco::Dynamic::Var params)
{
auto target_pubkey = getTargetPubkey(params);
Poco::UInt32 amount = 0;
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
try {
paramJsonObject->get("amount").convert(amount);
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
}
Poco::JSON::Object* JsonCreateTransaction::creation(Poco::Dynamic::Var params)
{
auto target_pubkey = getTargetPubkey(params);
Poco::UInt32 amount = 0;
Poco::DateTime target_date;
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
try {
paramJsonObject->get("amount").convert(amount);
paramJsonObject->get("target_date").convert(target_date);
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
}
Poco::JSON::Object* JsonCreateTransaction::groupMemberUpdate(Poco::Dynamic::Var params)
{
if (mTargetGroup.isNull()) {
return stateError("target_group not found");
}
model::gradido::Transaction::create(mSession->getNewUser(), mTargetGroup);
return stateSuccess();
}
MemoryBin* JsonCreateTransaction::getTargetPubkey(Poco::Dynamic::Var params)
{
std::string email;
std::string target_username;
std::string target_pubkey_hex;
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
auto fields = paramJsonObject->getNames();
try {
for (auto it = fields.begin(); it != fields.end(); it++) {
if (*it == "target_email") {
paramJsonObject->get("target_email").convert(email);
break;
}
if (*it == "target_username") {
paramJsonObject->get("target_username").convert(target_username);
break;
}
if (*it == "target_pubkey") {
paramJsonObject->get("target_pubkey").convert(target_pubkey_hex);
break;
}
}
}
catch (Poco::Exception& ex) {
return nullptr;
}
auto user = controller::User::create();
int result_count = 0;
MemoryBin* result = nullptr;
if (email != "") {
result_count = user->load(email);
}
else if (target_username != "") {
int group_id = 0;
if (!mTargetGroup.isNull()) {
group_id = mTargetGroup->getModel()->getID();
} else {
mSession->getNewUser()->getModel()->getGroupId();
}
result_count = user->getModel()->loadFromDB({ "username", "group_id" }, target_username, group_id, model::table::MYSQL_CONDITION_AND);
}
else if (target_pubkey_hex != "") {
result = DataTypeConverter::hexToBin(target_pubkey_hex);
}
if (1 == result_count) {
result = user->getModel()->getPublicKeyCopy();
}
return result;
}
bool JsonCreateTransaction::getTargetGroup(Poco::Dynamic::Var params)
{
std::string target_group_alias;
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
try
{
auto target_group = paramJsonObject->get("target_group");
if (!target_group.isEmpty()) {
target_group.convert(target_group_alias);
auto groups = controller::Group::load(target_group_alias);
if (groups.size() == 1) {
mTargetGroup = groups[0];
return true;
}
}
}
catch (Poco::Exception& ex) {
return false;
}
return false;
}

View File

@ -0,0 +1,26 @@
#ifndef __JSON_INTERFACE_JSON_CREATE_TRANSACTION_
#define __JSON_INTERFACE_JSON_CREATE_TRANSACTION_
#include "JsonRequestHandler.h"
#include "../SingletonManager/SessionManager.h"
#include "../controller/Group.h"
class JsonCreateTransaction : public JsonRequestHandler
{
public:
JsonCreateTransaction() : mSession(nullptr) {}
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
Poco::JSON::Object* transfer(Poco::Dynamic::Var params);
Poco::JSON::Object* creation(Poco::Dynamic::Var params);
Poco::JSON::Object* groupMemberUpdate(Poco::Dynamic::Var params);
MemoryBin* getTargetPubkey(Poco::Dynamic::Var params);
bool getTargetGroup(Poco::Dynamic::Var params);
Session* mSession;
std::string mMemo;
Poco::AutoPtr<controller::Group> mTargetGroup;
};
#endif // __JSON_INTERFACE_JSON_CREATE_TRANSACTION_

View File

@ -4,13 +4,14 @@
#include "../SingletonManager/SessionManager.h"
#include "JsonAdminEmailVerificationResend.h"
#include "JsonCreateTransaction.h"
#include "JsonCreateUser.h"
#include "JsonGetLogin.h"
#include "JsonUnknown.h"
#include "JsonTransaction.h"
#include "JsonGetRunningUserTasks.h"
#include "JsonGetUsers.h"
#include "JsonAdminEmailVerificationResend.h"
#include "JsonGetUserInfos.h"
#include "JsonUpdateUserInfos.h"
#include "JsonUnsecureLogin.h"
@ -47,6 +48,9 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c
else if (url_first_part == "/checkTransaction") {
return new JsonTransaction;
}
else if (url_first_part == "/createTransaction") {
return new JsonCreateTransaction;
}
else if (url_first_part == "/getRunningUserTasks") {
return new JsonGetRunningUserTasks;
}

View File

@ -32,6 +32,18 @@ namespace controller {
}
return resultVector;
}
Poco::AutoPtr<Group> Group::load(int id)
{
auto db = new model::table::Group();
if (1 == db->loadFromDB("id", id)) {
return new Group(db);
}
else {
return nullptr;
}
}
std::vector<Poco::AutoPtr<Group>> Group::listAll()
{

View File

@ -17,6 +17,7 @@ namespace controller {
static Poco::AutoPtr<Group> create(const std::string& alias, const std::string& name, const std::string& url, const std::string& description);
static std::vector<Poco::AutoPtr<Group>> load(const std::string& alias);
static Poco::AutoPtr<Group> load(int id);
static std::vector<Poco::AutoPtr<Group>> listAll();
inline bool deleteFromDB() { return mDBModel->deleteFromDB(); }

View File

@ -277,6 +277,22 @@ namespace DataTypeConverter
return microseconds;
}
void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::Timestamp* protoTimestamp)
{
auto microsecondsTotal = pocoTimestamp.epochMicroseconds();
auto secondsTotal = pocoTimestamp.epochTime();
protoTimestamp->set_seconds(secondsTotal);
protoTimestamp->set_nanos((microsecondsTotal - secondsTotal * pocoTimestamp.resolution()) * 1000);
}
void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::gradido::Timestamp* protoTimestamp)
{
auto microsecondsTotal = pocoTimestamp.epochMicroseconds();
auto secondsTotal = pocoTimestamp.epochTime();
protoTimestamp->set_seconds(secondsTotal);
protoTimestamp->set_nanos((microsecondsTotal - secondsTotal * pocoTimestamp.resolution()) * 1000);
}
Poco::Timestamp convertFromProtoTimestampSeconds(const proto::gradido::TimestampSeconds& timestampSeconds)
{
google::protobuf::int64 microseconds = timestampSeconds.seconds() * (google::protobuf::int64)10e5;

View File

@ -51,6 +51,8 @@ namespace DataTypeConverter {
std::string convertTimespanToLocalizedString(Poco::Timespan duration, LanguageCatalog* lang);
Poco::Timestamp convertFromProtoTimestamp(const proto::Timestamp& timestamp);
void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::Timestamp* protoTimestamp);
void convertToProtoTimestamp(const Poco::Timestamp pocoTimestamp, proto::gradido::Timestamp* protoTimestamp);
Poco::Timestamp convertFromProtoTimestampSeconds(const proto::gradido::TimestampSeconds& timestampSeconds);
Poco::Timespan convertFromProtoDuration(const proto::Duration& duration);
};

View File

@ -101,5 +101,32 @@ namespace model {
auto user_pubkey = mProtoMemberUpdate.user_pubkey();
return DataTypeConverter::binToHex((const unsigned char*)user_pubkey.data(), user_pubkey.size());
}
void GroupMemberUpdate::transactionAccepted(Poco::AutoPtr<controller::User> user)
{
static const char* function_name = "GroupMemberUpdate::transactionAccepted";
auto sm = SessionManager::getInstance();
auto target_group = mProtoMemberUpdate.target_group();
if (sm->isValid(target_group, VALIDATE_GROUP_ALIAS)) {
auto groups = controller::Group::load(mProtoMemberUpdate.target_group());
if (groups.size() != 1) {
addError(new ParamError(function_name, "target group not known or not unambiguous: ", target_group));
sendErrorsAsEmail();
}
else {
auto user_model = user->getModel();
auto group_model = groups[0]->getModel();
// write new group_id in user table
user_model->setGroupId(group_model->getID());
user_model->updateIntoDB("group_id", group_model->getID());
}
}
else {
addError(new ParamError(function_name, "invalid group alias, after transaction was successfully sended: ", target_group));
sendErrorsAsEmail();
}
}
}
}

View File

@ -18,6 +18,8 @@ namespace model {
std::string getTargetGroupAlias() { return mProtoMemberUpdate.target_group(); }
std::string getPublicKeyHex();
void transactionAccepted(Poco::AutoPtr<controller::User>);
protected:
const proto::gradido::GroupMemberUpdate& mProtoMemberUpdate;
};

View File

@ -44,19 +44,134 @@ namespace model {
Poco::AutoPtr<Transaction> Transaction::create(Poco::AutoPtr<controller::User> user, Poco::AutoPtr<controller::Group> group)
{
auto em = ErrorManager::getInstance();
static const char* function_name = "Transaction::create group member update";
if (user.isNull() || !user->getModel() || group.isNull() || !group->getModel()) {
return nullptr;
}
auto group_model = group->getModel();
auto network_type = table::HEDERA_TESTNET;
auto topic_id = controller::HederaId::find(group_model->getID(), network_type);
if (topic_id.isNull()) {
em->addError(new ParamError(function_name, "could'n find topic for group: ", group_model->getID()));
em->addError(new ParamError(function_name, "network type: ", network_type));
em->sendErrorsAsEmail();
return nullptr;
}
auto body = TransactionBody::create("", user, proto::gradido::GroupMemberUpdate_MemberUpdateType_ADD_USER, group_model->getAlias());
Poco::AutoPtr<Transaction> result = new Transaction(body);
auto model = result->getModel();
model->setHederaId(topic_id->getModel()->getID());
result->insertPendingTaskIntoDB(user, model::table::TASK_TYPE_GROUP_ADD_MEMBER);
PendingTasksManager::getInstance()->addTask(result);
return result;
}
Poco::AutoPtr<Transaction> Transaction::create(Poco::AutoPtr<controller::User> receiver, Poco::UInt32 amount, Poco::DateTime targetDate, const std::string& memo)
{
auto em = ErrorManager::getInstance();
static const char* function_name = "Transaction::create creation";
if (receiver.isNull() || !receiver->getModel()) {
return nullptr;
}
auto network_type = table::HEDERA_TESTNET;
auto receiver_model = receiver->getModel();
auto topic_id = controller::HederaId::find(receiver_model->getGroupId(), network_type);
if (topic_id.isNull()) {
em->addError(new ParamError(function_name, "could'n find topic for group: ", receiver_model->getGroupId()));
em->addError(new ParamError(function_name, "network type: ", network_type));
em->sendErrorsAsEmail();
return nullptr;
}
auto body = TransactionBody::create(memo, receiver, amount, targetDate);
Poco::AutoPtr<Transaction> result = new Transaction(body);
auto model = result->getModel();
model->setHederaId(topic_id->getModel()->getID());
result->insertPendingTaskIntoDB(receiver, model::table::TASK_TYPE_CREATION);
PendingTasksManager::getInstance()->addTask(result);
return result;
}
std::vector<Poco::AutoPtr<Transaction>> Transaction::create(Poco::AutoPtr<controller::User> sender, MemoryBin* receiverPubkey, Poco::AutoPtr<controller::Group> receiverGroup, Poco::UInt32 amount, const std::string& memo)
{
std::vector<Poco::AutoPtr<Transaction>> results;
auto em = ErrorManager::getInstance();
static const char* function_name = "Transaction::create transfer";
if (sender.isNull() || !sender->getModel() || receiverGroup.isNull() || !receiverGroup->getModel() || !receiverPubkey || !amount) {
return results;
}
//std::vector<Poco::AutoPtr<TransactionBody>> bodys;
auto sender_model = sender->getModel();
auto group_model = receiverGroup->getModel();
auto network_type = table::HEDERA_TESTNET;
// LOCAL Transfer
if (sender_model->getGroupId() == group_model->getID())
{
auto body = TransactionBody::create(memo, sender, receiverPubkey, amount);
Poco::AutoPtr<Transaction> transaction = new Transaction(body);
auto topic_id = controller::HederaId::find(sender_model->getGroupId(), network_type);
if (topic_id.isNull()) {
em->addError(new ParamError(function_name, "could'n find topic for group: ", sender_model->getGroupId()));
em->addError(new ParamError(function_name, "network type: ", network_type));
em->sendErrorsAsEmail();
return results;
}
transaction->getModel()->setHederaId(topic_id->getModel()->getID());
results.push_back(transaction);
}
else
{
auto sender_group = controller::Group::load(sender_model->getGroupId());
Poco::AutoPtr<controller::Group> transaction_group;
Poco::AutoPtr<controller::Group> topic_group;
// default constructor set it to now
Poco::Timestamp pairedTransactionId;
for (int i = 0; i < 2; i++) {
if (0 == i) {
transaction_group = receiverGroup;
topic_group = sender_group;
}
else {
transaction_group = sender_group;
topic_group = receiverGroup;
}
auto topic_id = controller::HederaId::find(topic_group->getModel()->getID(), network_type);
if (topic_id.isNull()) {
em->addError(new ParamError(function_name, "could'n find topic for group: ", sender_model->getGroupId()));
em->addError(new ParamError(function_name, "network type: ", network_type));
em->sendErrorsAsEmail();
return results;
}
if (transaction_group.isNull()) {
em->addError(new ParamError(function_name, "transaction group is zero, i:", i));
em->sendErrorsAsEmail();
return results;
}
auto body = TransactionBody::create(memo, sender, receiverPubkey, amount, pairedTransactionId, transaction_group);
Poco::AutoPtr<Transaction> transaction = new Transaction(body);
transaction->getModel()->setHederaId(topic_id->getModel()->getID());
results.push_back(transaction);
}
}
for (auto it = results.begin(); it != results.end(); it++) {
(*it)->insertPendingTaskIntoDB(sender, model::table::TASK_TYPE_TRANSFER);
PendingTasksManager::getInstance()->addTask(*it);
}
return results;
}
Poco::AutoPtr<Transaction> Transaction::load(model::table::PendingTask* dbModel)
{
proto::gradido::GradidoTransaction transaction_temp;
@ -333,8 +448,9 @@ namespace model {
// send transaction via hedera
auto network_type = table::HEDERA_TESTNET;
// TODO: get correct topic id for user group
int user_group_id = 1;
auto topic_id = controller::HederaId::find(user_group_id, network_type);
//int user_group_id = 1;
//auto topic_id = controller::HederaId::find(user_group_id, network_type);
auto topic_id = controller::HederaId::load(getModel()->getHederaId());
auto hedera_operator_account = controller::HederaAccount::pick(network_type, false);
if (!topic_id.isNull() && !hedera_operator_account.isNull())
@ -357,9 +473,9 @@ namespace model {
hedera_transaction.sign(crypto_key->getKeyPair(), std::move(hedera_transaction_body));
HederaRequest hedera_request;
HederaTask hedera_task(this);
Poco::AutoPtr<HederaTask> hedera_task(new HederaTask(this));
if (HEDERA_REQUEST_RETURN_OK != hedera_request.request(&hedera_transaction, &hedera_task))
if (HEDERA_REQUEST_RETURN_OK != hedera_request.request(&hedera_transaction, hedera_task))
{
addError(new Error(function_name, "error send transaction to hedera"));
getErrors(&hedera_request);
@ -367,7 +483,7 @@ namespace model {
return -2;
}
else {
auto hedera_transaction_response = hedera_task.getTransactionResponse();
auto hedera_transaction_response = hedera_task->getTransactionResponse();
auto hedera_precheck_code_string = hedera_transaction_response->getPrecheckCodeString();
auto precheck_code = hedera_transaction_response->getPrecheckCode();
auto cost = hedera_transaction_response->getCost();
@ -377,6 +493,12 @@ namespace model {
int zahl = 0;
return -5;
}
else if (precheck_code == proto::OK) {
// simply assume if transaction was sended to hedera without error, it was also accepted from gradido node
// TODO: later check, but now I haven't any way to communicate with the gradido node
mTransactionBody->getTransactionBase()->transactionAccepted(getUser());
return 1;
}
}
//model::hedera::TransactionBody hedera_transaction_body()
@ -391,7 +513,7 @@ namespace model {
else
{
addError(new Error(function_name, "hedera topic id or operator account not found!"));
addError(new ParamError(function_name, "user group id: ", user_group_id));
addError(new ParamError(function_name, "topic id: ", topic_id->getModel()->toString()));
addError(new ParamError(function_name, "network type: ", network_type));
sendErrorsAsEmail();
return -4;
@ -412,10 +534,14 @@ namespace model {
int SendTransactionTask::run()
{
auto result = mTransaction->runSendTransaction();
// delete because of error
if (-1 == result) {
mTransaction->deleteFromDB();
}
// delete because succeed, maybe change later
if (1 == result) {
mTransaction->deleteFromDB();
}
return 0;
}

View File

@ -26,7 +26,13 @@ namespace model {
~Transaction();
// create group add member transaction
// groupMemberUpdate
static Poco::AutoPtr<Transaction> create(Poco::AutoPtr<controller::User> user, Poco::AutoPtr<controller::Group> group);
//! \brief transfer
//! \return for cross group transaction return two transactions
static std::vector<Poco::AutoPtr<Transaction>> create(Poco::AutoPtr<controller::User> sender, MemoryBin* receiverPubkey, Poco::AutoPtr<controller::Group> receiverGroup, Poco::UInt32 amount, const std::string& memo);
static Poco::AutoPtr<Transaction> create(Poco::AutoPtr<controller::User> receiver, Poco::UInt32 amount, Poco::DateTime targetDate, const std::string& memo);
static Poco::AutoPtr<Transaction> load(model::table::PendingTask* dbModel);
bool sign(Poco::AutoPtr<controller::User> user);

View File

@ -15,6 +15,8 @@
#include "../proto/gradido/BasicTypes.pb.h"
#include "../SingletonManager/MemoryManager.h"
#include "../controller/User.h"
namespace model {
namespace gradido {
@ -54,6 +56,9 @@ namespace model {
inline Poco::UInt32 getMinSignatureCount() { return mMinSignatureCount; }
// called after sending transaction over hedera and after they was accepted from gradido node (at least one)
virtual void transactionAccepted(Poco::AutoPtr<controller::User> user) = 0;
protected:
std::string mMemo;
Poco::UInt32 mMinSignatureCount;

View File

@ -36,6 +36,81 @@ namespace model {
return obj;
}
Poco::AutoPtr<TransactionBody> TransactionBody::create(const std::string& memo, Poco::AutoPtr<controller::User> sender, MemoryBin* receiverPublicKey, Poco::UInt32 amount, Poco::Timestamp pairedTransactionId, Poco::AutoPtr<controller::Group> group/* = nullptr*/)
{
if (sender.isNull() || !sender->getModel()) {
return nullptr;
}
auto sender_model = sender->getModel();
Poco::AutoPtr<TransactionBody> obj = new TransactionBody;
obj->mTransactionBody.set_memo(memo);
auto gradido_transfer = obj->mTransactionBody.mutable_transfer();
proto::gradido::TransferAmount* transfer_amount = nullptr;
std::string* receiver = nullptr;
if (group.isNull())
{
auto local = gradido_transfer->mutable_local();
transfer_amount = local->mutable_sender();
receiver = local->mutable_receiver();
}
else
{
auto group_model = group->getModel();
proto::gradido::CrossGroupTransfer* cross_group_transfer = nullptr;
if (group->getModel()->getID() == sender->getModel()->getGroupId()) {
cross_group_transfer = gradido_transfer->mutable_outbound();
}
else {
cross_group_transfer = gradido_transfer->mutable_inbound();
}
transfer_amount = cross_group_transfer->mutable_sender();
receiver = cross_group_transfer->mutable_receiver();
auto paired_transaction_id = cross_group_transfer->mutable_paired_transaction_id();
DataTypeConverter::convertToProtoTimestamp(pairedTransactionId, paired_transaction_id);
cross_group_transfer->set_other_group(group_model->getAlias());
}
transfer_amount->set_amount(amount);
transfer_amount->set_pubkey(sender_model->getPublicKey(), sender_model->getPublicKeySize());
*receiver = std::string((const char*)*receiverPublicKey, receiverPublicKey->size());
obj->mType = TRANSACTION_TRANSFER;
obj->mTransactionSpecific = new TransactionTransfer(memo, obj->mTransactionBody.transfer());
obj->mTransactionSpecific->prepare();
return obj;
}
Poco::AutoPtr<TransactionBody> TransactionBody::load(const std::string& memo, Poco::AutoPtr<controller::User> receiver, Poco::UInt32 amount, Poco::DateTime targetDate)
{
if (receiver.isNull() || !receiver->getModel()) {
return nullptr;
}
auto receiver_model = receiver->getModel();
Poco::AutoPtr<TransactionBody> obj = new TransactionBody;
obj->mTransactionBody.set_memo(memo);
auto creation = obj->mTransactionBody.mutable_creation();
auto target_date_timestamp_seconds = creation->mutable_target_date();
target_date_timestamp_seconds->set_seconds(targetDate.timestamp().epochTime());
auto transfer_amount = creation->mutable_receiver();
transfer_amount->set_amount(amount);
std::string* pubkey_str = transfer_amount->mutable_pubkey();
*pubkey_str = std::string((const char*)receiver_model->getPublicKey(), receiver_model->getPublicKeySize());
obj->mType = TRANSACTION_CREATION;
obj->mTransactionSpecific = new TransactionCreation(memo, obj->mTransactionBody.creation());
obj->mTransactionSpecific->prepare();
return obj;
}
Poco::AutoPtr<TransactionBody> TransactionBody::load(const std::string& protoMessageBin)
{
Poco::AutoPtr<TransactionBody> obj = new TransactionBody;

View File

@ -28,7 +28,16 @@ namespace model {
public:
~TransactionBody();
//! \brief GroupMemberUpdate Transaction
static Poco::AutoPtr<TransactionBody> create(const std::string& memo, Poco::AutoPtr<controller::User> user, proto::gradido::GroupMemberUpdate_MemberUpdateType type, const std::string& targetGroupAlias);
//! \brief GradidoTransfer Transaction
//! \param group if group.isNull() it is a local transfer, else cross group transfer,
//! \param group if group is same as sender group outbound, else inbound
static Poco::AutoPtr<TransactionBody> create(const std::string& memo, Poco::AutoPtr<controller::User> sender, MemoryBin* receiverPublicKey, Poco::UInt32 amount, Poco::Timestamp pairedTransactionId = Poco::Timestamp(), Poco::AutoPtr<controller::Group> group = nullptr);
//! \brief GradidoCreation Transaction
static Poco::AutoPtr<TransactionBody> create(const std::string& memo, Poco::AutoPtr<controller::User> receiver, Poco::UInt32 amount, Poco::DateTime targetDate);
static Poco::AutoPtr<TransactionBody> load(const std::string& protoMessageBin);
inline TransactionType getType() { lock(); auto t = mType; unlock(); return t; }

View File

@ -117,6 +117,11 @@ namespace model {
return TRANSACTION_VALID_OK;
}
void TransactionCreation::transactionAccepted(Poco::AutoPtr<controller::User> user)
{
}
}
}

View File

@ -36,6 +36,8 @@ namespace model {
inline std::string getAmountString() { return amountToString(getAmount()); }
std::string getTargetDateString();
void transactionAccepted(Poco::AutoPtr<controller::User> user);
protected:
const proto::gradido::GradidoCreation& mProtoCreation;
char mReceiverPublicHex[65];

View File

@ -179,6 +179,12 @@ namespace model {
return mKontoTable[index].amountCell;
}
void TransactionTransfer::transactionAccepted(Poco::AutoPtr<controller::User> user)
{
}
}
}

View File

@ -32,6 +32,8 @@ namespace model {
const std::string& getKontoNameCell(int index);
const std::string& getAmountCell(int index);
void transactionAccepted(Poco::AutoPtr<controller::User> user);
protected:
const static std::string mInvalidIndexMessage;

View File

@ -20,8 +20,9 @@ namespace model
}
PendingTask::PendingTask(const PendingTaskTuple& tuple)
: ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mRequest(tuple.get<2>()), mCreated(tuple.get<3>()), mFinished(tuple.get<4>()),
mResultJsonString(tuple.get<5>()), mTaskTypeId(tuple.get<6>()), mChildPendingTaskId(tuple.get<7>()), mParentPendingTaskId(tuple.get<8>())
: ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mHederaId(tuple.get<2>()),
mRequest(tuple.get<3>()), mCreated(tuple.get<4>()), mFinished(tuple.get<5>()),
mResultJsonString(tuple.get<6>()), mTaskTypeId(tuple.get<7>()), mChildPendingTaskId(tuple.get<8>()), mParentPendingTaskId(tuple.get<9>())
{
}
@ -113,9 +114,9 @@ namespace model
{
Poco::Data::Statement select(session);
select << "SELECT id, user_id, request, created, finished, result_json, task_type_id, child_pending_task_id, parent_pending_task_id FROM " << getTableName()
select << "SELECT id, user_id, hedera_id, request, created, finished, result_json, task_type_id, child_pending_task_id, parent_pending_task_id FROM " << getTableName()
<< " where " << fieldName << " = ?"
, into(mID), into(mUserId), into(mRequest), into(mCreated), into(mFinished), into(mResultJsonString),
, into(mID), into(mUserId), into(mHederaId), into(mRequest), into(mCreated), into(mFinished), into(mResultJsonString),
into(mTaskTypeId), into(mChildPendingTaskId), into(mParentPendingTaskId);
return select;
@ -125,7 +126,7 @@ namespace model
{
Poco::Data::Statement select(session);
select << "SELECT id, user_id, request, created, finished, result_json, task_type_id, child_pending_task_id, parent_pending_task_id FROM " << getTableName();
select << "SELECT id, user_id, hedera_id, request, created, finished, result_json, task_type_id, child_pending_task_id, parent_pending_task_id FROM " << getTableName();
return select;
}
@ -149,8 +150,8 @@ namespace model
Poco::Data::Statement insert(session);
lock();
insert << "INSERT INTO " << getTableName()
<< " (user_id, request, created, task_type_id, child_pending_task_id, parent_pending_task_id) VALUES(?,?,?,?,?,?)"
, use(mUserId), use(mRequest), use(mCreated), use(mTaskTypeId), use(mChildPendingTaskId), use(mParentPendingTaskId);
<< " (user_id, hedera_id, request, created, task_type_id, child_pending_task_id, parent_pending_task_id) VALUES(?,?,?,?,?,?)"
, use(mUserId), use(mHederaId), use(mRequest), use(mCreated), use(mTaskTypeId), use(mChildPendingTaskId), use(mParentPendingTaskId);
unlock();
return insert;
}

View File

@ -21,7 +21,7 @@ namespace model {
};
typedef Poco::Tuple<int, int, Poco::Data::BLOB, Poco::DateTime, Poco::DateTime, std::string, int, int, int> PendingTaskTuple;
typedef Poco::Tuple<int, int, int, Poco::Data::BLOB, Poco::DateTime, Poco::DateTime, std::string, int, int, int> PendingTaskTuple;
class PendingTask : public ModelBase
{
@ -41,6 +41,7 @@ namespace model {
bool updateRequest();
inline int getUserId() const { SHARED_LOCK; return mUserId; }
inline int getHederaId() const { SHARED_LOCK; return mHederaId; }
inline const std::vector<unsigned char>& getRequest() const { SHARED_LOCK; return mRequest.content(); }
inline std::string getRequestCopy() const { SHARED_LOCK; return std::string((const char*)mRequest.content().data(), mRequest.content().size()); }
inline Poco::DateTime getCreated() const { SHARED_LOCK; return mCreated; }
@ -49,6 +50,7 @@ namespace model {
inline int getParentPendingTaskId() const { SHARED_LOCK; return mParentPendingTaskId; }
inline void setUserId(int userId) { UNIQUE_LOCK; mUserId = userId; }
inline void setHederaId(int hederaId) { UNIQUE_LOCK; mHederaId = hederaId; }
void setRequest(const std::string& serializedProto);
inline void setTaskType(TaskType type) { UNIQUE_LOCK; mTaskTypeId = type; }
inline void setChildPendingTaskId(int childPendingTaskId) {UNIQUE_LOCK; mChildPendingTaskId = childPendingTaskId;}
@ -67,6 +69,7 @@ namespace model {
Poco::Data::Statement _insertIntoDB(Poco::Data::Session session);
int mUserId;
int mHederaId;
Poco::Data::BLOB mRequest;
Poco::DateTime mCreated;
Poco::DateTime mFinished;

View File

@ -26,8 +26,8 @@ namespace model {
//id, first_name, last_name, email, pubkey, created, email_checked
User::User(UserTuple tuple)
: ModelBase(tuple.get<0>()),
mFirstName(tuple.get<1>()), mLastName(tuple.get<2>()), mEmail(tuple.get<3>()),
mPublicKey(tuple.get<4>()), mCreated(tuple.get<5>()), mEmailChecked(tuple.get<6>()), mDisabled(tuple.get<7>()), mGroupId(tuple.get<8>()),
mFirstName(tuple.get<1>()), mLastName(tuple.get<2>()), mEmail(tuple.get<3>()), mUsername(tuple.get<4>()),
mPublicKey(tuple.get<5>()), mCreated(tuple.get<6>()), mEmailChecked(tuple.get<7>()), mDisabled(tuple.get<8>()), mGroupId(tuple.get<9>()),
mPasswordHashed(0), mLanguageKey("de"), mRole(ROLE_NOT_LOADED)
{
@ -80,12 +80,12 @@ namespace model {
if (mPasswordHashed) {
insert << "INSERT INTO users (email, first_name, last_name, password, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?);",
use(mEmail), use(mFirstName), use(mLastName), bind(mPasswordHashed), use(mEmailHash), use(mLanguageKey), use(mGroupId);
insert << "INSERT INTO users (email, first_name, last_name, username, password, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?);",
use(mEmail), use(mFirstName), use(mLastName), use(mUsername), bind(mPasswordHashed), use(mEmailHash), use(mLanguageKey), use(mGroupId);
}
else {
insert << "INSERT INTO users (email, first_name, last_name, email_hash, language, group_id) VALUES(?,?,?,?,?,?);",
use(mEmail), use(mFirstName), use(mLastName), use(mEmailHash), use(mLanguageKey), use(mGroupId);
insert << "INSERT INTO users (email, first_name, last_name, username, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?);",
use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mEmailHash), use(mLanguageKey), use(mGroupId);
}
return insert;
@ -98,11 +98,11 @@ namespace model {
_fieldName = getTableName() + std::string(".id");
}
Poco::Data::Statement select(session);
select << "SELECT " << getTableName() << ".id, email, first_name, last_name, password, pubkey, privkey, email_hash, created, email_checked, language, disabled, group_id, user_roles.role_id "
select << "SELECT " << getTableName() << ".id, email, first_name, last_name, username, password, pubkey, privkey, email_hash, created, email_checked, language, disabled, group_id, user_roles.role_id "
<< " FROM " << getTableName()
<< " LEFT JOIN user_roles ON " << getTableName() << ".id = user_roles.user_id "
<< " WHERE " << _fieldName << " = ?" ,
into(mID), into(mEmail), into(mFirstName), into(mLastName), into(mPasswordHashed),
into(mID), into(mEmail), into(mFirstName), into(mLastName), into(mUsername), into(mPasswordHashed),
into(mPublicKey), into(mPrivateKey), into(mEmailHash), into(mCreated), into(mEmailChecked),
into(mLanguageKey), into(mDisabled), into(mGroupId), into(mRole);
@ -114,7 +114,7 @@ namespace model {
{
Poco::Data::Statement select(session);
// typedef Poco::Tuple<std::string, std::string, std::string, Poco::Nullable<Poco::Data::BLOB>, int> UserTuple;
select << "SELECT id, first_name, last_name, email, pubkey, created, email_checked, disabled, group_id FROM " << getTableName()
select << "SELECT id, first_name, last_name, email, username, pubkey, created, email_checked, disabled, group_id FROM " << getTableName()
<< " where " << fieldName << " LIKE ?";
@ -130,7 +130,7 @@ namespace model {
}
// typedef Poco::Tuple<std::string, std::string, std::string, Poco::Nullable<Poco::Data::BLOB>, int> UserTuple;
select << "SELECT id, first_name, last_name, email, pubkey, created, email_checked, disabled, group_id FROM " << getTableName()
select << "SELECT id, first_name, last_name, email, username, pubkey, created, email_checked, disabled, group_id FROM " << getTableName()
<< " where " << fieldNames[0] << " LIKE ?";
if (conditionType == MYSQL_CONDITION_AND) {
for (int i = 1; i < fieldNames.size(); i++) {
@ -242,8 +242,8 @@ namespace model {
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement update(session);
update << "UPDATE users SET first_name = ?, last_name = ?, disabled = ?, language = ? where id = ?;",
use(mFirstName), use(mLastName), use(mDisabled), use(mLanguageKey), use(mID);
update << "UPDATE users SET first_name = ?, last_name = ?, username = ?, disabled = ?, language = ? where id = ?;",
use(mFirstName), use(mLastName), use(mUsername), use(mDisabled), use(mLanguageKey), use(mID);
try {
@ -301,7 +301,7 @@ namespace model {
sodium_bin2hex(*email_hash, crypto_generichash_BYTES + 1, mEmailHash.value().content().data(), mEmailHash.value().content().size());
}
ss << mUsername << std::endl;
ss << mFirstName << " " << mLastName << " <" << mEmail << ">" << std::endl;
ss << "password hash: " << mPasswordHashed << std::endl;
ss << "public key: " << (char*)*pubkeyHex << std::endl;
@ -338,7 +338,8 @@ namespace model {
if (!mEmailHash.isNull()) {
sodium_bin2hex(*email_hash, crypto_generichash_BYTES + 1, mEmailHash.value().content().data(), mEmailHash.value().content().size());
}
ss << "<b>" << mUsername << "</b><br>";
ss << "<b>" << mFirstName << " " << mLastName << " <" << mEmail << "></b>" << "<br>";
ss << "public key: " << (char*)*pubkeyHex << "<br>";
ss << "email hash: " << (char*)*email_hash << "<br>";
@ -371,6 +372,17 @@ namespace model {
return pubkeyHexString;
}
MemoryBin* User::getPublicKeyCopy() const
{
SHARED_LOCK;
auto mm = MemoryManager::getInstance();
auto public_key_size = getPublicKeySize();
if (!public_key_size) return nullptr;
auto pubkey = mm->getFreeMemory(getPublicKeySize());
memcpy(*pubkey, getPublicKey(), public_key_size);
return pubkey;
}
std::string User::getPrivateKeyEncryptedHex() const
{
std::shared_lock<std::shared_mutex> _lock(mSharedMutex);
@ -400,6 +412,7 @@ namespace model {
userObj.set("first_name", mFirstName);
userObj.set("last_name", mLastName);
userObj.set("email", mEmail);
userObj.set("username", mUsername);
//userObj.set("state", userStateToString(mState));
auto createTimeStamp = mCreated.timestamp();

View File

@ -28,7 +28,7 @@ namespace model {
USER_FIELDS_LANGUAGE
};
typedef Poco::Tuple<int, std::string, std::string, std::string, Poco::Nullable<Poco::Data::BLOB>, Poco::DateTime, int, int, int> UserTuple;
typedef Poco::Tuple<int, std::string, std::string, std::string, std::string, Poco::Nullable<Poco::Data::BLOB>, Poco::DateTime, int, int, int> UserTuple;
class User : public ModelBase
{
@ -56,10 +56,13 @@ namespace model {
inline const std::string getEmail() const { SHARED_LOCK; return mEmail; }
inline const std::string getFirstName() const { SHARED_LOCK; return mFirstName; }
inline const std::string getLastName() const { SHARED_LOCK; return mLastName; }
inline const std::string getUsername() const { SHARED_LOCK; return mUsername; }
inline std::string getNameWithEmailHtml() const { SHARED_LOCK; return mFirstName + "&nbsp;" + mLastName + "&nbsp;&lt;" + mEmail + "&gt;"; }
inline const Poco::UInt64 getPasswordHashed() const { SHARED_LOCK; return mPasswordHashed; }
inline int getGroupId() const { SHARED_LOCK; return mGroupId; }
inline RoleType getRole() const { SHARED_LOCK; if (mRole.isNull()) return ROLE_NONE; return static_cast<RoleType>(mRole.value()); }
inline const unsigned char* getPublicKey() const { SHARED_LOCK; if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); }
MemoryBin* getPublicKeyCopy() const;
inline size_t getPublicKeySize() const { SHARED_LOCK; if (mPublicKey.isNull()) return 0; return mPublicKey.value().content().size(); }
std::string getPublicKeyHex() const;
std::string getPrivateKeyEncryptedHex() const;
@ -71,12 +74,12 @@ namespace model {
inline bool isEmailChecked() const { SHARED_LOCK; return mEmailChecked; }
inline const std::string getLanguageKey() const { SHARED_LOCK; return mLanguageKey; }
inline bool isDisabled() const { SHARED_LOCK; return mDisabled; }
inline int getGroupId() const { SHARED_LOCK; return mGroupId; }
// default setter unlocked
void setEmail(const std::string& email);
inline void setFirstName(const std::string& first_name) { UNIQUE_LOCK; mFirstName = first_name; }
inline void setLastName(const std::string& last_name) { UNIQUE_LOCK; mLastName = last_name; }
inline void setUsername(const std::string& username) { UNIQUE_LOCK; mUsername = username; }
inline void setPasswordHashed(const Poco::UInt64& passwordHashed) { UNIQUE_LOCK; mPasswordHashed = passwordHashed; }
void setPublicKey(const unsigned char* publicKey);
//! \brief set encrypted private key
@ -85,6 +88,7 @@ namespace model {
inline void setEmailChecked(bool emailChecked) { UNIQUE_LOCK; mEmailChecked = emailChecked; }
inline void setLanguageKey(const std::string& languageKey) { UNIQUE_LOCK; mLanguageKey = languageKey; }
inline void setDisabled(bool disabled) { UNIQUE_LOCK; mDisabled = disabled; }
inline void setGroupId(int groupId) { UNIQUE_LOCK; mGroupId = groupId; }
Poco::JSON::Object getJson();
@ -100,6 +104,7 @@ namespace model {
std::string mEmail;
std::string mFirstName;
std::string mLastName;
std::string mUsername;
Poco::UInt64 mPasswordHashed;