From 2862d7824d18017a0ad8a4e5fcd60637c83b9fed Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Tue, 4 Feb 2020 17:43:13 +0000 Subject: [PATCH] Adding Notification Emails and make larger textbox for creation transactions --- .../JsonRequestHandlerController.php | 3 + src/Form/CreationForm.php | 2 +- src/Model/Entity/StateUser.php | 8 + src/Model/Transactions/Transaction.php | 5 +- src/Model/Transactions/TransactionBase.php | 24 ++- src/Model/Transactions/TransactionBody.php | 21 ++- .../Transactions/TransactionCreation.php | 34 +++- .../Transactions/TransactionTransfer.php | 41 ++++- src/Template/Element/printGradido.ctp | 7 +- src/Template/StateErrors/show_for_user.ctp | 2 +- ...actionJsonRequestHandlerControllerTest.php | 174 ------------------ 11 files changed, 132 insertions(+), 189 deletions(-) delete mode 100644 tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php diff --git a/src/Controller/JsonRequestHandlerController.php b/src/Controller/JsonRequestHandlerController.php index 20cfac267..c6fd1dbc6 100644 --- a/src/Controller/JsonRequestHandlerController.php +++ b/src/Controller/JsonRequestHandlerController.php @@ -6,6 +6,7 @@ use App\Controller\AppController; use Cake\ORM\TableRegistry; use Cake\Routing\Router; + use Model\Transactions\Transaction; /*! * @author: Dario Rekowski# @@ -63,6 +64,8 @@ class JsonRequestHandlerController extends AppController { } if ($transaction->save()) { + + // success return $this->returnJson(['state' => 'success']); } else { diff --git a/src/Form/CreationForm.php b/src/Form/CreationForm.php index fbb4a4ded..8a80d7a18 100644 --- a/src/Form/CreationForm.php +++ b/src/Form/CreationForm.php @@ -15,7 +15,7 @@ class CreationForm extends Form //->addField('receiver_pubkey_hex', ['type' => 'string']) ->addField('receiver', ['type' => 'select']) ->addField('amount', ['type' => 'decimal', 'precision' => 2]) - ->addField('memo', ['type' =>'string', 'default' => '']); + ->addField('memo', ['type' =>'text', 'default' => '', 'rows' => 5, 'maxlength' => 150]); } function validationDefault(Validator $validator) diff --git a/src/Model/Entity/StateUser.php b/src/Model/Entity/StateUser.php index a6e8c40da..1824be430 100644 --- a/src/Model/Entity/StateUser.php +++ b/src/Model/Entity/StateUser.php @@ -43,4 +43,12 @@ class StateUser extends Entity 'transaction_creations' => true, 'transaction_send_coins' => true ]; + + public function getEmailWithName() { + return $this->first_name . ' ' . $this->last_name . ' <' . $this->email . '>'; + } + + public function getNames() { + return $this->first_name . ' ' . $this->last_name; + } } diff --git a/src/Model/Transactions/Transaction.php b/src/Model/Transactions/Transaction.php index 220d20287..71e9039b1 100644 --- a/src/Model/Transactions/Transaction.php +++ b/src/Model/Transactions/Transaction.php @@ -151,9 +151,10 @@ class Transaction extends TransactionBase { return false; } - - $connection->commit(); + + $this->mTransactionBody->getSpecificTransaction()->sendNotificationEmail($this->mTransactionBody->getMemo()); + return true; } diff --git a/src/Model/Transactions/TransactionBase.php b/src/Model/Transactions/TransactionBase.php index bf55e34cc..4198fbaaa 100644 --- a/src/Model/Transactions/TransactionBase.php +++ b/src/Model/Transactions/TransactionBase.php @@ -6,6 +6,7 @@ use Cake\ORM\TableRegistry; class TransactionBase { private $errors = []; + static $stateUsersTable = null; public function getErrors() { return $this->errors; @@ -23,8 +24,18 @@ class TransactionBase { return count($this->errors) > 0; } + public static function getStateUsersTable() + { + if(!self::$stateUsersTable) { + self::$stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); + } + return self::$stateUsersTable; + } + + protected function getStateUserId($publicKey) { - $stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); + + $stateUsersTable = self::getStateUsersTable(); $stateUser = $stateUsersTable->find('all')->select(['id'])->where(['public_key' => $publicKey])->first(); if($stateUser) { return $stateUser->id; @@ -41,6 +52,17 @@ class TransactionBase { return NULL; } + protected function getStateUser($id) { + $stateUsersTable = self::getStateUsersTable(); + $stateUser = $stateUsersTable->get($id); + if($stateUser) { + return $stateUser; + } + + return NULL; + } + + protected function updateStateBalance($stateUserId, $addAmountCent) { $finalBalance = 0; $stateBalancesTable = TableRegistry::getTableLocator()->get('stateBalances'); diff --git a/src/Model/Transactions/TransactionBody.php b/src/Model/Transactions/TransactionBody.php index 5025aec08..1d14a4c26 100644 --- a/src/Model/Transactions/TransactionBody.php +++ b/src/Model/Transactions/TransactionBody.php @@ -90,10 +90,15 @@ class TransactionBody extends TransactionBase { $previousTxHash = null; if($this->mTransactionID > 1) { try { - $previousTransaction = $transactionsTable->get($this->mTransactionID - 1, [ + $previousTransaction = $transactionsTable + ->find('all', ['contain' => false]) + ->select(['tx_hash']) + ->where(['id' => $this->mTransactionID - 1]) + ->first(); + /*$previousTransaction = $transactionsTable->get($this->mTransactionID - 1, [ 'contain' => false, 'fields' => ['tx_hash'] - ]); + ]);*/ } catch(Cake\Datasource\Exception\RecordNotFoundException $ex) { $this->addError('TransactionBody::save', 'previous transaction (with id ' . ($this->mTransactionID-1) . ' not found'); return false; @@ -105,7 +110,17 @@ class TransactionBody extends TransactionBase { } $previousTxHash = $previousTransaction->tx_hash; } - $transactionEntity->received = $transactionsTable->get($transactionEntity->id, ['contain' => false, 'fields' => ['received']])->received; + try { + //$transactionEntity->received = $transactionsTable->get($transactionEntity->id, ['contain' => false, 'fields' => ['received']])->received; + $transactionEntity->received = $transactionsTable + ->find('all', ['contain' => false]) + ->where(['id' => $transactionEntity->id]) + ->select(['received'])->first()->received; + } catch(Cake\Datasource\Exception\RecordNotFoundException $ex) { + $this->addError('TransactionBody::save', 'current transaction (with id ' . ($transactionEntity->id) . ' not found'); + $this->addError('exception: ', $ex->getMessage()); + return false; + } // calculate tx hash // previous tx hash + id + received + sigMap as string diff --git a/src/Model/Transactions/TransactionCreation.php b/src/Model/Transactions/TransactionCreation.php index c2da4fed7..7627fb1c8 100644 --- a/src/Model/Transactions/TransactionCreation.php +++ b/src/Model/Transactions/TransactionCreation.php @@ -5,6 +5,8 @@ namespace Model\Transactions; //use App\Model\Transactions\TransactionBase; use Cake\ORM\TableRegistry; +use Cake\Core\Configure; +use Cake\Mailer\Email; class TransactionCreation extends TransactionBase { @@ -135,12 +137,12 @@ class TransactionCreation extends TransactionBase { // state user id //$state_user_id = $this->getStateUserId($firstPublic); - $receiverUser = $this->getStateUserId($this->getReceiverPublic()); - if(!$receiverUser) { + $receiverUserId = $this->getStateUserId($this->getReceiverPublic()); + if(!$receiverUserId) { $this->addError('TransactionCreation::save', 'couldn\'t get state user id'); return false; } - $transactionCreationEntity->state_user_id = $receiverUser; + $transactionCreationEntity->state_user_id = $receiverUserId; $transactionCreationEntity->amount = $this->getAmount(); $transactionCreationEntity->ident_hash = $this->getIdentHash(); @@ -150,10 +152,34 @@ class TransactionCreation extends TransactionBase { } // update state balance - if(false === $this->updateStateBalance($receiverUser, $this->getAmount())) { + if(false === $this->updateStateBalance($receiverUserId, $this->getAmount())) { return false; } + + return true; + } + + public function sendNotificationEmail($memo) + { + // send notification email + $receiverUserId = $this->getStateUserId($this->getReceiverPublic()); + $receiverUser = $this->getStateUser($receiverUserId); + $noReplyEmail = Configure::read('noReplyEmail'); + + try { + $email = new Email(); + $emailViewBuilder = $email->viewBuilder(); + $emailViewBuilder->setTemplate('notificationCreation') + ->setVars(['user' => $receiverUser, 'gdd_cent' => $this->getAmount(), 'memo' => $memo]); + $email->setFrom([$noReplyEmail => 'Nicht antworten']) + ->setTo([$receiverUser->email => $receiverUser->getNames()]) + ->setSubject(__('Gradido Schöpfung erhalten')) + ->send(); + } catch(Exception $e) { + $this->addError('TransactionCreation::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); + return false; + } return true; } diff --git a/src/Model/Transactions/TransactionTransfer.php b/src/Model/Transactions/TransactionTransfer.php index a4ac93027..a82173a28 100644 --- a/src/Model/Transactions/TransactionTransfer.php +++ b/src/Model/Transactions/TransactionTransfer.php @@ -4,6 +4,8 @@ namespace Model\Transactions; //use App\Model\Transactions\TransactionBase; use Cake\ORM\TableRegistry; +use Cake\Core\Configure; +use Cake\Mailer\Email; class TransactionTransfer extends TransactionBase { private $protoTransactionTransfer; @@ -167,7 +169,7 @@ class TransactionTransfer extends TransactionBase { $senderAmount = $this->protoTransactionTransfer->getSenderAmounts()[0]; if(count($this->protoTransactionTransfer->getReceiverAmounts()) !== 1) { - $this->addError($functionName, 'not more tahn one receiver currently supported'); + $this->addError($functionName, 'not more than one receiver currently supported'); return false; } $receiverAmount = $this->protoTransactionTransfer->getReceiverAmounts()[0]; @@ -201,11 +203,48 @@ class TransactionTransfer extends TransactionBase { return false; } + + + //$this->addError('TransactionTransfer::save', 'not implemented yet'); //return false; return true; } + public function sendNotificationEmail($memo) + { + // send notification email + + $senderAmount = $this->protoTransactionTransfer->getSenderAmounts()[0]; + $receiverAmount = $this->protoTransactionTransfer->getReceiverAmounts()[0]; + $senderUserId = $this->getStateUserId($senderAmount->getEd25519SenderPubkey()); + $receiverUserId = $this->getStateUserId($receiverAmount->getEd25519ReceiverPubkey()); + + $receiverUser = $this->getStateUser($receiverUserId); + $senderUser = $this->getStateUser($senderUserId); + $serverAdminEmail = Configure::read('ServerAdminEmail'); + + try { + $email = new Email(); + $emailViewBuilder = $email->viewBuilder(); + $emailViewBuilder->setTemplate('notificationTransfer') + ->setVars(['receiverUser' => $receiverUser, + 'senderUser' => $senderUser, + 'gdd_cent' => $receiverAmount->getAmount(), + 'memo' => $memo]); + + $email->setFrom([$serverAdminEmail => $senderUser->getNames() . ' via Gradido Community']) + ->setTo([$receiverUser->email => $receiverUser->getNames()]) + ->setReplyTo($senderUser->email) + ->setSubject(__('Gradidos erhalten')) + ->send(); + } catch(Exception $e) { + $this->addError('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); + return false; + } + return true; + } + static public function fromEntity($transactionTransferEntity) { $protoTransfer = new \Model\Messages\Gradido\Transfer(); diff --git a/src/Template/Element/printGradido.ctp b/src/Template/Element/printGradido.ctp index f8ac29eb6..6544c585c 100644 --- a/src/Template/Element/printGradido.ctp +++ b/src/Template/Element/printGradido.ctp @@ -15,7 +15,10 @@ if($number < 0) { $class = 'grd-negative-currency'; } -?> +?> +Number->format(intval($number) / 10000.0, ['precision' => 2]) . ' GDD';?> + Number->format(intval($number) / 10000.0, ['precision' => 2]) . ' GDD';?> - \ No newline at end of file + + \ No newline at end of file diff --git a/src/Template/StateErrors/show_for_user.ctp b/src/Template/StateErrors/show_for_user.ctp index d2dda0562..a73f59dfc 100644 --- a/src/Template/StateErrors/show_for_user.ctp +++ b/src/Template/StateErrors/show_for_user.ctp @@ -24,7 +24,7 @@ $this->assign('title', __('Fehlermeldungen')); $type = $transactionTypes[$error->transaction_type_id-1]; $errorMessage = ""; $errorArray = json_decode($error->message_json, true); - if(isset($errorArray['details'])) { + if(isset($errorArray['details']) && is_array($errorArray['details'])) { foreach($errorArray['details'][0] as $function => $errorString) { $errorMessage = '' . $function . '
' . $errorString; diff --git a/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php b/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php deleted file mode 100644 index 7ad28760c..000000000 --- a/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php +++ /dev/null @@ -1,174 +0,0 @@ - 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQJ8wF12eZo3hcMAlAKKJ9WLT-zuSkNmGh7D98UEqH4KoIysnCkXqEya9EBZl9o11_nJ8xmm_nOevuVjR-GfLMQ8qSQoOSGFsbG8gV2VsdCAxMjMSBgiZm4ruBUovCicKIJSuE1uTzZ8zdStOVcQZA6P6oTp1u5C_1BHqHUoaXnEfEKDakwEQtYntlgo', - 'validCreation900' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQNVZ8Ae3Zbg3G0wZ840fzKan6N4KtTcSe0KYi17kQwFmsl18oFxXv8_s6j1xXFrIKjy1_1Olq0a7xYLErDMkjwYqORIGCNb5iu4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgNHKCBC1ie2WCg', - 'validCreation1200' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQEEey5QMAdldoOTP_jTETHgOQriGsixEY0cziQeRfT_J5YtbI_A6AizEYD-JcxmRmXzv1xjjTgsV39Y32ta2CQkqORIGCIeGi-4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgOy4CxC1ie2WCg', - 'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3', - 'validTransfer' => 'GmYKZAoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0SQDddHyKzAX3LBV0PuDiPc6lxkUipss5tyuLRpMtFJQnT30tsbYIkA1FXimjMKOoiuLswf4OLLV3bAIYehW-b9AgqYQoFSGFsbG8SBgiJlaPvBUJQCiYKIIGQvaWF7l8dn799BugeaewY4TN2EEz_VLdFfrfT73ENEICfSRImCiDtdleSLxhUgEbMW9DpqIwsykFj3-z_enKEOuGnXrmW8xCAn0k', - 'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ==' - ]; - - /*public function setUp() { - parent::setUp(); - } -*/ - public function testWrongMethod() - { - $this->configRequest([ - 'headers' => ['Accept' => 'application/json'] - ]); - $this->get('/TransactionJsonRequestHandler'); - $this->assertResponseOk(); - - $expected = json_encode(['state' => 'error', 'msg' => 'no post']); - $this->assertEquals($expected, (string)$this->_response->getBody()); - } - - public function testInvalidJson() - { - $this->configRequest([ - 'headers' => ['Accept' => 'application/json'] - ]); - $this->post('/TransactionJsonRequestHandler', '{This isn\'t valid json}'); - $this->assertResponseOk(); - - $expected = json_encode(['state' => 'error', 'msg' => 'parameter error']); - $this->assertEquals($expected, (string)$this->_response->getBody()); - } - - public function testNotSetTransaction() - { - $this->postAndParse( - ['method' => 'putTransaction'], - ['state' => 'error', 'msg' => 'parameter error'] - ); - } - public function testNotSetMethod() - { - $this->postAndParse( - ['transaction' => $this->transactions['validCreation']], - ['state' => 'error', 'msg' => 'parameter error'] - ); - } - - public function testUnknownMethod() - { - //$this->post('/TransactionJsonRequestHandler', ['method' => 'putTransaction', 'transaction' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3/cHHaWchkUhWiGhQjB23xCg2pMBELWJ7ZYK']); - $this->postAndParse( - ['method' => 'foobar', 'transaction' => $this->transactions['validCreation']], - ['state' => 'error', 'msg' => 'unknown method', 'details' => 'foobar'] - ); - - } - - public function testInvalidEncodedTransaction() { - //"msg":"error parsing transaction","details":[{"Transaction":"base64 decode error"}] - $this->postAndParse( - ['method' => 'putTransaction', 'transaction' => $this->transactions['notBase64']], - ['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [ - ['Transaction' => 'invalid base64 string'] - ]] - ); - } - - public function testInvalidTransaction() { - - $this->postAndParse( - ['method' => 'putTransaction', 'transaction' => base64_encode('Hallo Miau Welt')], - ['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [ - ['Transaction' => 'Error occurred during parsing: Unexpected wire type.'] - ]] - ); - } - - public function testToLargeCreationSum() - { - $this->postAndParse( - ['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation900']], - '{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}' - ); - } - - public function testToLargeCreation() - { - $this->postAndParse( - ['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation1200']], - '{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}' - ); - } - - public function testValidTransfer() - { - $this->postAndParse( - ['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']], - ['state' => 'success'] - ); - } - - /*public function testMissingPreviousTransaction() - { - - }*/ - - public function testValidTransaction() - { - $this->postAndParse( - ['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']], - ['state' => 'success'] - ); - } - - private function postAndParse($params, $expected) - { - - $this->configRequest([ - 'headers' => ['Accept' => 'application/json'] - ]); - - $this->disableErrorHandlerMiddleware(); - $this->post('/TransactionJsonRequestHandler', json_encode($params)); - - // Check that the response was a 200 - $this->assertResponseOk(); - - $responseBodyString = (string)$this->_response->getBody(); - $json = json_decode($responseBodyString); - $this->assertNotFalse($json); - - if(is_array($expected)) { - $expected = json_encode($expected); - } - $this->assertEquals($expected, $responseBodyString); - } -}