adding new files

This commit is contained in:
Dario Rekowski on RockPI 2019-11-07 13:15:34 +00:00
parent 3a15bd320c
commit fed853f348
32 changed files with 872 additions and 63 deletions

View File

@ -2,6 +2,7 @@
namespace App\Controller;
use App\Controller\AppController;
use Cake\I18n\Number;
/**
* AddressTypes Controller

View File

@ -15,7 +15,8 @@
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
//use Cake\Event\Event;
use Cake\ORM\TableRegistry;
/**
* Application Controller
@ -75,6 +76,25 @@ class AppController extends Controller
* see https://book.cakephp.org/3.0/en/controllers/components/security.html
*/
//$this->loadComponent('Security');
// load current balance
$session = $this->getRequest()->getSession();
$state_user_id = $session->read('StateUser.id');
if($state_user_id) {
$stateBalancesTable = TableRegistry::getTableLocator()->get('stateBalances');
$stateBalanceEntry = $stateBalancesTable
->find('all')
->select('amount')
->contain(false)
->where(['state_user_id' => $state_user_id]);
if($stateBalanceEntry->count() == 1) {
//var_dump($stateBalanceEntry->first());
$session->write('StateUser.balance', $stateBalanceEntry->first()->amount);
//echo "stateUser.balance: " . $session->read('StateUser.balance');
}
}
//echo "initialize";
}
/*
public function beforeFilter(Event $event)

View File

@ -0,0 +1,33 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace App\Controller\Component;
use Cake\Controller\Component;
class GradidoNumberComponent extends Component
{
// input can be from 0,01 or 0.01 up to big number be anything
static public function parseInputNumberToCentNumber($inputNumber)
{
//$filteredInputNumber = preg_replace('/,/', '.', $inputNumber);
$parts = preg_split('/(,|\.)/', (string)$inputNumber);
$result = intval($parts[0]) * 10000;
if(count($parts) == 2) {
$result += intval($parts[1]) * 100;
}
return $result;
}
static public function centToPrint($centAmount)
{
}
}

View File

@ -21,7 +21,7 @@ class DashboardController extends AppController
{
parent::initialize();
//$this->Auth->allow(['add', 'edit']);
$this->Auth->allow('index');
$this->Auth->allow(['index', 'errorHttpRequest']);
}
/**
* Index method
@ -58,8 +58,11 @@ class DashboardController extends AppController
$loginServer = Configure::read('LoginServer');
$url = $loginServer['host'] . ':' . $loginServer['port'];
//$url = 'http://***REMOVED***';
$requestStart = microtime(true);
$response = $http->get($url . '/login', ['session_id' => $session_id]);
$json = $response->getJson();
$requestEnd = microtime(true);
if(isset($json) && count($json) > 0) {
@ -70,13 +73,18 @@ class DashboardController extends AppController
if($key === 'state') { continue; }
$session->write('StateUser.' . $key, $value );
}
$transactionPendings = $json['Transaction.pending'];
$session->write('Transaction.pending', $transactionPendings);
//echo "read transaction pending: $transactionPendings<br>";
$session->write('Transactions.pending', $transactionPendings);
$session->write('session_id', $session_id);
$stateUserTable = TableRegistry::getTableLocator()->get('StateUsers');
if($json['user']['public_hex'] != '') {
$public_key_bin = hex2bin($json['user']['public_hex']);
$stateUserQuery = $stateUserTable->find('all')->where(['public_key' => $public_key_bin]);
$stateUserQuery = $stateUserTable
->find('all')
->where(['public_key' => $public_key_bin])
->contain(['StateBalances']);
if($stateUserQuery->count() == 1) {
$stateUser = $stateUserQuery->first();
if($stateUser->first_name != $json['user']['first_name'] ||
@ -87,7 +95,11 @@ class DashboardController extends AppController
$this->Flash->error(__('error updating state user ' . json_encode($stateUser->errors())));
}
}
$session->write('StateUser.id', $stateUser['id']);
//var_dump($stateUser);
if(count($stateUser->state_balances) > 0) {
$session->write('StateUser.balance', $stateUser->state_balances[0]->amount);
}
$session->write('StateUser.id', $stateUser->id);
//echo $stateUser['id'];
} else {
$newStateUser = $stateUserTable->newEntity();
@ -109,6 +121,7 @@ class DashboardController extends AppController
$this->set('user', $json['user']);
//$this->set('json', $json);
$this->set('timeUsed', microtime(true) - $startTime);
$this->set('requestTime', $requestEnd - $requestStart);
} else {
if($json['state'] === 'not found' ) {
@ -124,7 +137,7 @@ class DashboardController extends AppController
} catch(\Exception $e) {
$msg = $e->getMessage();
$this->Flash->error(__('error http request: ') . $msg);
return $this->redirect(['controller' => 'Dashboard', 'action' => 'errorHttpRequest']);
//continue;
}
} else {
@ -139,6 +152,13 @@ class DashboardController extends AppController
return $this->redirect(Router::url('/', true) . 'account/', 303);
}
}
public function errorHttpRequest()
{
$startTime = microtime(true);
$this->viewBuilder()->setLayout('frontend');
$this->set('timeUsed', microtime(true) - $startTime);
}
}

View File

@ -12,6 +12,13 @@ use App\Controller\AppController;
*/
class StateBalancesController extends AppController
{
public function initialize()
{
parent::initialize();
//$this->Auth->allow(['add', 'edit']);
$this->Auth->allow(['overview']);
}
/**
* Index method
*
@ -26,6 +33,11 @@ class StateBalancesController extends AppController
$this->set(compact('stateBalances'));
}
public function overview()
{
$this->viewBuilder()->setLayout('frontend');
}
/**
* View method

View File

@ -0,0 +1,113 @@
<?php
namespace App\Controller;
use App\Controller\AppController;
/**
* StateErrors Controller
*
* @property \App\Model\Table\StateErrorsTable $StateErrors
*
* @method \App\Model\Entity\StateError[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
*/
class StateErrorsController extends AppController
{
/**
* Index method
*
* @return \Cake\Http\Response|null
*/
public function index()
{
$this->paginate = [
'contain' => ['StateUsers', 'TransactionTypes']
];
$stateErrors = $this->paginate($this->StateErrors);
$this->set(compact('stateErrors'));
}
/**
* View method
*
* @param string|null $id State Error id.
* @return \Cake\Http\Response|null
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function view($id = null)
{
$stateError = $this->StateErrors->get($id, [
'contain' => ['StateUsers', 'TransactionTypes']
]);
$this->set('stateError', $stateError);
}
/**
* Add method
*
* @return \Cake\Http\Response|null Redirects on successful add, renders view otherwise.
*/
public function add()
{
$stateError = $this->StateErrors->newEntity();
if ($this->request->is('post')) {
$stateError = $this->StateErrors->patchEntity($stateError, $this->request->getData());
if ($this->StateErrors->save($stateError)) {
$this->Flash->success(__('The state error has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The state error could not be saved. Please, try again.'));
}
$stateUsers = $this->StateErrors->StateUsers->find('list', ['limit' => 200]);
$transactionTypes = $this->StateErrors->TransactionTypes->find('list', ['limit' => 200]);
$this->set(compact('stateError', 'stateUsers', 'transactionTypes'));
}
/**
* Edit method
*
* @param string|null $id State Error id.
* @return \Cake\Http\Response|null Redirects on successful edit, renders view otherwise.
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function edit($id = null)
{
$stateError = $this->StateErrors->get($id, [
'contain' => []
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$stateError = $this->StateErrors->patchEntity($stateError, $this->request->getData());
if ($this->StateErrors->save($stateError)) {
$this->Flash->success(__('The state error has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The state error could not be saved. Please, try again.'));
}
$stateUsers = $this->StateErrors->StateUsers->find('list', ['limit' => 200]);
$transactionTypes = $this->StateErrors->TransactionTypes->find('list', ['limit' => 200]);
$this->set(compact('stateError', 'stateUsers', 'transactionTypes'));
}
/**
* Delete method
*
* @param string|null $id State Error id.
* @return \Cake\Http\Response|null Redirects to index.
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function delete($id = null)
{
$this->request->allowMethod(['post', 'delete']);
$stateError = $this->StateErrors->get($id);
if ($this->StateErrors->delete($stateError)) {
$this->Flash->success(__('The state error has been deleted.'));
} else {
$this->Flash->error(__('The state error could not be deleted. Please, try again.'));
}
return $this->redirect(['action' => 'index']);
}
}

View File

@ -4,7 +4,7 @@ namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
use Cake\Routing\Router;
use Cake\I18n\Number;
//use Cake\I18n\Number;
use Cake\Http\Client;
use Cake\Core\Configure;
@ -27,6 +27,7 @@ class TransactionCreationsController extends AppController
public function initialize()
{
parent::initialize();
$this->loadComponent('GradidoNumber');
//$this->Auth->allow(['add', 'edit']);
$this->Auth->allow('create');
}
@ -99,12 +100,9 @@ class TransactionCreationsController extends AppController
$pubKeyHex = '';
$receiver = new ReceiverAmount();
//echo 'amount: ' . $requestData['amount'] . '<br>';
$floatAmount = floatval(Number::format($requestData['amount'], ['places' => 4, 'locale' => 'en_GB']));
//echo 'set for receiver: ' . round($floatAmount * 10000) . '<br>';
$receiver->setAmount(round($floatAmount * 10000));
//echo 'after receiver amount set<br>';
$receiver->setAmount($this->GradidoNumber->parseInputNumberToCentNumber($requestData['amount']));
if(intval($requestData['receiver']) == 0) {
if(strlen($requestData['receiver_pubkey_hex']) != 64) {
$this->Flash->error(__('Invalid public Key, must contain 64 Character'));
@ -119,7 +117,9 @@ class TransactionCreationsController extends AppController
}
}
if($pubKeyHex != '') {
$receiver->setEd25519ReceiverPubkey(hex2bin($pubKeyHex));
$pubKeyBin = hex2bin($pubKeyHex);
$receiver->setEd25519ReceiverPubkey($pubKeyBin);
//var_dump($requestData);
$creationDate = new TimestampSeconds();

View File

@ -0,0 +1,68 @@
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
use Model\Transactions\Transaction;
/*!
* @author: Dario Rekowski#
*
* @date: 03.11.2019
*
* @desc: Handle requests from other server put or request transaction
*/
class TransactionJsonRequestHandlerController extends AppController {
public function initialize()
{
parent::initialize();
//$this->Auth->allow(['add', 'edit']);
$this->Auth->allow('index');
}
public function index()
{
if($this->request->is('post')) {
$jsonData = $this->request->input('json_decode');
//var_dump($jsonData);
if($jsonData == NULL || !isset($jsonData->method) || !isset($jsonData->transaction)) {
return $this->returnJson(['state' => 'error', 'msg' => 'parameter error']);
}
$method = $jsonData->method;
switch($method) {
case 'putTransaction': return $this->putTransaction($jsonData->transaction);
}
return $this->returnJson(['state' => 'error', 'msg' => 'unknown method', 'details' => $method]);
}
return $this->returnJson(['state' => 'error', 'msg' => 'no post']);
}
private function putTransaction($transactionBase64) {
$transaction = new Transaction($transactionBase64);
if($transaction->hasErrors()) {
return $this->returnJson(['state' => 'error', 'msg' => 'error parsing transaction', 'details' => $transaction->getErrors()]);
}
if(!$transaction->validate()) {
return $this->returnJson(['state' => 'error', 'msg' => 'error validate transaction', 'details' => $transaction->getErrors()]);
}
if ($transaction->save()) {
// success
return $this->returnJson(['state' => 'success']);
} else {
return $this->returnJson([
'state' => 'error',
'msg' => 'error saving transaction in db',
'details' => json_encode($transaction->getErrors())
]);
}
return $this->returnJson(['state' => 'success']);
}
}

View File

@ -35,7 +35,12 @@ class CreationForm extends Form
'rule' => ['maxLength', 150],
'message' => 'max 150 character'
])
->ascii('memo', __('Only Ascii Character allowed'))
//->alphaNumeric('memo', __('Only Alpha Numeric Character allowed'))
->add('memo', 'custom', [
'rule' => 'alphaNumeric',
'provider' => 'custom',
'message' => __('Only Alpha Numeric Character allowed')
])
->allowEmptyString('memo', null, 'create')
/*->add('receiver_pubkey_hex', 'custom', [
'rule' => 'hexKey64',

View File

@ -0,0 +1,37 @@
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
/**
* StateError Entity
*
* @property int $id
* @property int $state_user_id
* @property int $transaction_type_id
* @property \Cake\I18n\FrozenTime $created
* @property string $message_json
*
* @property \App\Model\Entity\StateUser $state_user
* @property \App\Model\Entity\TransactionType $transaction_type
*/
class StateError extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* @var array
*/
protected $_accessible = [
'state_user_id' => true,
'transaction_type_id' => true,
'created' => true,
'message_json' => true,
'state_user' => true,
'transaction_type' => true
];
}

View File

@ -0,0 +1,88 @@
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
/**
* StateErrors Model
*
* @property \App\Model\Table\StateUsersTable&\Cake\ORM\Association\BelongsTo $StateUsers
* @property \App\Model\Table\TransactionTypesTable&\Cake\ORM\Association\BelongsTo $TransactionTypes
*
* @method \App\Model\Entity\StateError get($primaryKey, $options = [])
* @method \App\Model\Entity\StateError newEntity($data = null, array $options = [])
* @method \App\Model\Entity\StateError[] newEntities(array $data, array $options = [])
* @method \App\Model\Entity\StateError|false save(\Cake\Datasource\EntityInterface $entity, $options = [])
* @method \App\Model\Entity\StateError saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = [])
* @method \App\Model\Entity\StateError patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
* @method \App\Model\Entity\StateError[] patchEntities($entities, array $data, array $options = [])
* @method \App\Model\Entity\StateError findOrCreate($search, callable $callback = null, $options = [])
*
* @mixin \Cake\ORM\Behavior\TimestampBehavior
*/
class StateErrorsTable extends Table
{
/**
* Initialize method
*
* @param array $config The configuration for the Table.
* @return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('state_errors');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('StateUsers', [
'foreignKey' => 'state_user_id',
'joinType' => 'INNER'
]);
$this->belongsTo('TransactionTypes', [
'foreignKey' => 'transaction_type_id',
'joinType' => 'INNER'
]);
}
/**
* Default validation rules.
*
* @param \Cake\Validation\Validator $validator Validator instance.
* @return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmptyString('id', null, 'create');
$validator
->scalar('message_json')
->requirePresence('message_json', 'create')
->notEmptyString('message_json');
return $validator;
}
/**
* Returns a rules checker object that will be used for validating
* application integrity.
*
* @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
* @return \Cake\ORM\RulesChecker
*/
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['state_user_id'], 'StateUsers'));
$rules->add($rules->existsIn(['transaction_type_id'], 'TransactionTypes'));
return $rules;
}
}

View File

@ -19,11 +19,19 @@ class Transaction extends TransactionBase {
private $mTransactionBody = null;
public function __construct($base64Data) {
$transactionBin = base64_decode($base64Data, true);
//$transactionBin = base64_decode($base64Data, true);
//if($transactionBin == false)
//sodium_base64_VARIANT_URLSAFE_NO_PADDING
try {
$transactionBin = sodium_base642bin($base64Data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING);
} catch(\SodiumException $e) {
$this->addError('Transaction', $e->getMessage());// . ' ' . $base64Data);
return;
}
//*/
if($transactionBin == false) {
//$this->addError('base64 decode failed');
$this->addError('Transaction', 'base64 decode error');
$this->addError('Transaction', 'base64 decode error: ' . $base64Data);
} else {
$this->mProtoTransaction = new \Model\Messages\Gradido\Transaction();
try {
@ -52,7 +60,14 @@ class Transaction extends TransactionBase {
}
public function validate() {
$sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair();
$sigMap = $this->mProtoTransaction->getSigMap();
if(!$sigMap) {
$this->addError('Transaction', 'signature map is zero');
return false;
}
//var_dump($sigMap);
//die();
$sigPairs = $sigMap->getSigPair();
$bodyBytes = $this->mProtoTransaction->getBodyBytes();
@ -98,7 +113,7 @@ class Transaction extends TransactionBase {
//signature pubkey
$sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair();
echo "sigPairs: "; var_dump($sigPairs);
//echo "sigPairs: "; var_dump($sigPairs);
$signatureEntitys = [];
foreach($sigPairs as $sigPair) {
$signatureEntity = $transactionsSignaturesTable->newEntity();

View File

@ -40,4 +40,30 @@ class TransactionBase {
return NULL;
}
protected function updateStateBalance($stateUserId, $newAmountCent) {
$stateBalancesTable = TableRegistry::getTableLocator()->get('stateBalances');
$stateBalanceQuery = $stateBalancesTable
->find('all')
->select(['amount'])
->contain(false)
->where(['state_user_id' => $stateUserId]);//->first();
//debug($stateBalanceQuery);
if($stateBalanceQuery->count() > 0) {
$stateBalanceEntry = $stateBalanceEntry->first();
$stateBalanceEntry->amount += $newAmountCent;
} else {
$stateBalanceEntry = $stateBalancesTable->newEntity();
$stateBalanceEntry->state_user_id = $stateUserId;
$stateBalanceEntry->amount = $newAmountCent;
}
if(!$stateBalancesTable->save($stateBalanceEntry)) {
$errors = $stateBalanceEntry->getErrors();
$this->addError('TransactionBase::updateStateBalance', 'error saving state balance with: ' . json_encode($errors));
return false;
}
return true;
}
}

View File

@ -11,7 +11,15 @@ class TransactionBody extends TransactionBase {
public function __construct($bodyBytes) {
$this->mProtoTransactionBody = new \Model\Messages\Gradido\TransactionBody();
$this->mProtoTransactionBody->mergeFromString($bodyBytes);
try {
$this->mProtoTransactionBody->mergeFromString($bodyBytes);
// cannot catch Exception with cakePHP, I don't know why
} catch(\Google\Protobuf\Internal\GPBDecodeException $e) {
//var_dump($e);
$this->addError('TransactionBody', $e->getMessage());
return;
}
switch($this->mProtoTransactionBody->getData()) {
case 'creation' : $this->mSpecificTransaction = new TransactionCreation($this->mProtoTransactionBody->getCreation()); break;
case 'transfer' : $this->mSpecificTransaction = new TransactionTransfer($this->mProtoTransactionBody->getTransfer()); break;
@ -20,7 +28,7 @@ class TransactionBody extends TransactionBase {
public function validate($sigPairs) {
// check if creation time is in the past
if($this->mProtoTransactionBody->getCreated() > time()) {
if($this->mProtoTransactionBody->getCreated()->getSeconds() > time()) {
$this->addError('TransactionBody::validate', 'Transaction were created in the past!');
return false;
}

View File

@ -40,22 +40,36 @@ class TransactionCreation extends TransactionBase {
}
// check if creation threshold for this month isn't reached
//$identHashBin = sprintf("%0d", $this->getIdentHash());
// padding with zero in case hash is smaller than 32 bytes, static length binary field in db
$identHashBin = pack('a32', $this->getIdentHash());
$existingCreations = $this->transactionCreationsTable
->find('all')
->group('ident_hash')
->where(['ident_hash' => $this->getIdentHash()]);
->where(['ident_hash' => $identHashBin]);
$existingCreations->select(['amount_sum' => $existingCreations->func()->sum('amount')]);
debug($existingCreations);
$existingCreations->matching('Transactions', function ($q) {
return $q->where(['EXTRACT(YEAR_MONTH FROM Transactions.received) LIKE EXTRACT(YEAR_MONTH FROM NOW())']);
});
//debug($existingCreations);
if($existingCreations->count() > 0) {
var_dump($existingCreations->toArray());
}
//var_dump($existingCreations->toArray());
//echo "amount sum: " . $existingCreations->first()->amount_sum . "\n";
if($this->getAmount() + $existingCreations->first()->amount_sum > 10000000) {
$this->addError('TransactionCreation::validate', 'Creation more than 1000 gr per Month not allowed');
return false;
}
}
//die("\n");
return true;
}
public function save($transaction_id, $firstPublic) {
public function save($transaction_id, $firstPublic)
{
$transactionCreationEntity = $this->transactionCreationsTable->newEntity();
$transactionCreationEntity->transaction_id = $transaction_id;
// state user id
@ -72,7 +86,12 @@ class TransactionCreation extends TransactionBase {
$this->addError('TransactionCreation::save', 'error saving transactionCreation with errors: ' . json_encode($transactionCreationEntity->getErrors()));
return false;
}
$receiverUser = $this->getStateUserId($this->getReceiverPublic());
// update state balance
if(!$this->updateStateBalance($receiverUser, $this->getAmount())) {
return false;
}
return true;
}

View File

@ -30,4 +30,11 @@ class TransactionValidation
}
return false;
}
public static function alphaNumeric($value, array $context) {
if(preg_match('/^[a-zA-Z0-9äöüÄÖÜß _-]*$/', $value)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,14 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
$this->assign('title', __('Error, Please try again'));
?>
<div class="grd_container_small">
<button class="grd_clickable grd-form-bn" onclick="history.back()"><?= __('Back'); ?></button>
</div>

View File

@ -11,6 +11,9 @@ if(isset($user)) {
}
$this->assign('title', __('Willkommen') . '&nbsp;' . $user['first_name'] . '&nbsp;' . $user['last_name']);
?>
<?php if(isset($requestTime)) : ?>
<span class='grd-second-timer'><?= round($requestTime * 1000.0) ?> ms</span>
<?php endif; ?>
<div class="grd_container_small">
<fieldset>
<h3>Gradido ...</h3>

View File

@ -1,5 +1,6 @@
<?php
use Cake\Routing\Router;
use App\Controller\Component\GradidoNumberComponent;
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
@ -14,9 +15,17 @@ use Cake\Routing\Router;
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
$cakeDescription = 'Gradido';
$session = $this->getRequest()->getSession();
$transactionPendings = $session->read('Transactions.pending');
$balance = $session->read('StateUser.balance');
//echo "balance: $balance<br>";
if(!isset($balance)) {
$balance = 0;
}
//echo "balance: $balance<br>";
//echo "transactions pending: " . $transactionPendings;
?>
<!DOCTYPE html>
@ -45,16 +54,22 @@ $transactionPendings = $session->read('Transactions.pending');
<nav class="grd-left-bar expanded" data-topbar role="navigation">
<div class="grd-left-bar-section">
<ul class="grd-no-style">
<?php if(isset($balance)) : ?>
<li><?= $this->Html->link($this->element('printGradido', ['number' => $balance]),
['controller' => 'StateBalances', 'action' => 'overview'], ['class' => 'grd-nav-bn grd-nav-without-border', 'escape' => false])
?>
</li>
<?php endif; ?>
<li><?= $this->Html->link(__('Startseite'), ['controller' => 'dashboard'], ['class' => 'grd-nav-bn'])?>
<!--<li><?= $this->Html->link(__('Kontostand'), ['controller' => 'StateBalances', 'action' => 'overview'], ['class' => 'grd-nav-bn']) ?>-->
<?php if(intval($transactionPendings) > 0) : ?>
<li>
<a href="<?= Router::url('', true) ?>account/checkTransactions" class="grd-nav-bn">
<a href="<?= Router::url('./', true) ?>account/checkTransactions" class="grd-nav-bn">
<?= __("Transaktionen unterzeichnen") . '&nbsp;(' . intval($transactionPendings) . ')'?>
</a>
</li>
<?php else: ?>
<li><a href="<?= Router::url('', true) ?>account/logout" class="grd-nav-bn"><?= __("Logout"); ?></a></li>
<li><a href="<?= Router::url('./', true) ?>account/logout" class="grd-nav-bn"><?= __("Logout"); ?></a></li>
<?php endif; ?>
</ul>
</div>

View File

@ -0,0 +1,8 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
$this->assign('title', __('Kontoübersicht'));

View File

@ -0,0 +1,29 @@
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\StateError $stateError
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('List State Errors'), ['action' => 'index']) ?></li>
<li><?= $this->Html->link(__('List State Users'), ['controller' => 'StateUsers', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New State User'), ['controller' => 'StateUsers', 'action' => 'add']) ?></li>
<li><?= $this->Html->link(__('List Transaction Types'), ['controller' => 'TransactionTypes', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New Transaction Type'), ['controller' => 'TransactionTypes', 'action' => 'add']) ?></li>
</ul>
</nav>
<div class="stateErrors form large-9 medium-8 columns content">
<?= $this->Form->create($stateError) ?>
<fieldset>
<legend><?= __('Add State Error') ?></legend>
<?php
echo $this->Form->control('state_user_id', ['options' => $stateUsers]);
echo $this->Form->control('transaction_type_id', ['options' => $transactionTypes]);
echo $this->Form->control('message_json');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>

View File

@ -0,0 +1,35 @@
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\StateError $stateError
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Form->postLink(
__('Delete'),
['action' => 'delete', $stateError->id],
['confirm' => __('Are you sure you want to delete # {0}?', $stateError->id)]
)
?></li>
<li><?= $this->Html->link(__('List State Errors'), ['action' => 'index']) ?></li>
<li><?= $this->Html->link(__('List State Users'), ['controller' => 'StateUsers', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New State User'), ['controller' => 'StateUsers', 'action' => 'add']) ?></li>
<li><?= $this->Html->link(__('List Transaction Types'), ['controller' => 'TransactionTypes', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New Transaction Type'), ['controller' => 'TransactionTypes', 'action' => 'add']) ?></li>
</ul>
</nav>
<div class="stateErrors form large-9 medium-8 columns content">
<?= $this->Form->create($stateError) ?>
<fieldset>
<legend><?= __('Edit State Error') ?></legend>
<?php
echo $this->Form->control('state_user_id', ['options' => $stateUsers]);
echo $this->Form->control('transaction_type_id', ['options' => $transactionTypes]);
echo $this->Form->control('message_json');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>

View File

@ -0,0 +1,55 @@
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\StateError[]|\Cake\Collection\CollectionInterface $stateErrors
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('New State Error'), ['action' => 'add']) ?></li>
<li><?= $this->Html->link(__('List State Users'), ['controller' => 'StateUsers', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New State User'), ['controller' => 'StateUsers', 'action' => 'add']) ?></li>
<li><?= $this->Html->link(__('List Transaction Types'), ['controller' => 'TransactionTypes', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New Transaction Type'), ['controller' => 'TransactionTypes', 'action' => 'add']) ?></li>
</ul>
</nav>
<div class="stateErrors index large-9 medium-8 columns content">
<h3><?= __('State Errors') ?></h3>
<table cellpadding="0" cellspacing="0">
<thead>
<tr>
<th scope="col"><?= $this->Paginator->sort('id') ?></th>
<th scope="col"><?= $this->Paginator->sort('state_user_id') ?></th>
<th scope="col"><?= $this->Paginator->sort('transaction_type_id') ?></th>
<th scope="col"><?= $this->Paginator->sort('created') ?></th>
<th scope="col" class="actions"><?= __('Actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($stateErrors as $stateError): ?>
<tr>
<td><?= $this->Number->format($stateError->id) ?></td>
<td><?= $stateError->has('state_user') ? $this->Html->link($stateError->state_user->id, ['controller' => 'StateUsers', 'action' => 'view', $stateError->state_user->id]) : '' ?></td>
<td><?= $stateError->has('transaction_type') ? $this->Html->link($stateError->transaction_type->name, ['controller' => 'TransactionTypes', 'action' => 'view', $stateError->transaction_type->id]) : '' ?></td>
<td><?= h($stateError->created) ?></td>
<td class="actions">
<?= $this->Html->link(__('View'), ['action' => 'view', $stateError->id]) ?>
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $stateError->id]) ?>
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $stateError->id], ['confirm' => __('Are you sure you want to delete # {0}?', $stateError->id)]) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="paginator">
<ul class="pagination">
<?= $this->Paginator->first('<< ' . __('first')) ?>
<?= $this->Paginator->prev('< ' . __('previous')) ?>
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next(__('next') . ' >') ?>
<?= $this->Paginator->last(__('last') . ' >>') ?>
</ul>
<p><?= $this->Paginator->counter(['format' => __('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')]) ?></p>
</div>
</div>

View File

@ -0,0 +1,44 @@
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\StateError $stateError
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('Edit State Error'), ['action' => 'edit', $stateError->id]) ?> </li>
<li><?= $this->Form->postLink(__('Delete State Error'), ['action' => 'delete', $stateError->id], ['confirm' => __('Are you sure you want to delete # {0}?', $stateError->id)]) ?> </li>
<li><?= $this->Html->link(__('List State Errors'), ['action' => 'index']) ?> </li>
<li><?= $this->Html->link(__('New State Error'), ['action' => 'add']) ?> </li>
<li><?= $this->Html->link(__('List State Users'), ['controller' => 'StateUsers', 'action' => 'index']) ?> </li>
<li><?= $this->Html->link(__('New State User'), ['controller' => 'StateUsers', 'action' => 'add']) ?> </li>
<li><?= $this->Html->link(__('List Transaction Types'), ['controller' => 'TransactionTypes', 'action' => 'index']) ?> </li>
<li><?= $this->Html->link(__('New Transaction Type'), ['controller' => 'TransactionTypes', 'action' => 'add']) ?> </li>
</ul>
</nav>
<div class="stateErrors view large-9 medium-8 columns content">
<h3><?= h($stateError->id) ?></h3>
<table class="vertical-table">
<tr>
<th scope="row"><?= __('State User') ?></th>
<td><?= $stateError->has('state_user') ? $this->Html->link($stateError->state_user->id, ['controller' => 'StateUsers', 'action' => 'view', $stateError->state_user->id]) : '' ?></td>
</tr>
<tr>
<th scope="row"><?= __('Transaction Type') ?></th>
<td><?= $stateError->has('transaction_type') ? $this->Html->link($stateError->transaction_type->name, ['controller' => 'TransactionTypes', 'action' => 'view', $stateError->transaction_type->id]) : '' ?></td>
</tr>
<tr>
<th scope="row"><?= __('Id') ?></th>
<td><?= $this->Number->format($stateError->id) ?></td>
</tr>
<tr>
<th scope="row"><?= __('Created') ?></th>
<td><?= h($stateError->created) ?></td>
</tr>
</table>
<div class="row">
<h4><?= __('Message Json') ?></h4>
<?= $this->Text->autoParagraph(h($stateError->message_json)); ?>
</div>
</div>

View File

@ -16,7 +16,7 @@ class StateBalancesFixture extends TestFixture
// @codingStandardsIgnoreStart
public $fields = [
'id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
'user_id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'state_user_id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'modified' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null],
'amount' => ['type' => 'biginteger', 'length' => 20, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'_constraints' => [
@ -38,9 +38,9 @@ class StateBalancesFixture extends TestFixture
$this->records = [
[
'id' => 1,
'user_id' => 1,
'state_user_id' => 1,
'modified' => '2019-11-05 18:02:28',
'amount' => 1
'amount' => 1200
],
];
parent::init();

View File

@ -42,12 +42,21 @@ class StateUsersFixture extends TestFixture
$this->records = [
[
'id' => 1,
'index_id' => 1,
'group_id' => 1,
'public_key' => 'Lorem ipsum dolor sit amet',
'email' => 'Lorem ipsum dolor sit amet',
'first_name' => 'Lorem ipsum dolor sit amet',
'last_name' => 'Lorem ipsum dolor sit amet'
'index_id' => 0,
'group_id' => 0,
'public_key' => '0x94ae135b93cd9f33752b4e55c41903a3faa13a75bb90bfd411ea1d4a1a5e711f',
'email' => NULL,
'first_name' => 'Dario',
'last_name' => 'Rekowski'
],
[
'id' => 11,
'index_id' => 0,
'group_id' => 0,
'public_key' => '0x61b923c218cb63a64a8c62f3860121283b9577f374d0a31590ba02cdc2912999',
'email' => NULL,
'first_name' => 'Dario',
'last_name' => 'Rekowski'
],
];
parent::init();

View File

@ -36,13 +36,21 @@ class TransactionCreationsFixture extends TestFixture
*/
public function init()
{
//(8, 17, 11, 1210000, 0x2d31333636313339343833000000000000000000000000000000000000000000)
$this->records = [
[
'id' => 1,
'transaction_id' => 1,
'state_user_id' => 1,
'amount' => 1,
'ident_hash' => 'Lorem ipsum dolor sit amet'
'state_user_id' => 11,
'amount' => 10000000,
'ident_hash' => hex2bin('2d31333636313339343833000000000000000000000000000000000000000000')
],
[
'id' => 8,
'transaction_id' => 17,
'state_user_id' => 11,
'amount' => 1210000,
'ident_hash' => hex2bin('2d31333636313339343833000000000000000000000000000000000000000000')
],
];
parent::init();

View File

@ -37,14 +37,23 @@ class TransactionsFixture extends TestFixture
*/
public function init()
{
//(17, 0, 1, 0x0000000000000000000000000000000000000000000000000000000000000000, '', '2019-11-05 15:13:27');
$this->records = [
[
'id' => 1,
'group_id' => 1,
'group_id' => 0,
'transaction_type_id' => 1,
'tx_hash' => 'Lorem ipsum dolor sit amet',
'memo' => 'Lorem ipsum dolor sit amet',
'received' => 1572973566
'tx_hash' => '0x0000000000000000000000000000000000000000000000000000000000000000',
'memo' => '',
'received' => 1571314633
],
[
'id' => 17,
'group_id' => 0,
'transaction_type_id' => 1,
'tx_hash' => '0x0000000000000000000000000000000000000000000000000000000000000000',
'memo' => '',
'received' => 1572966807
],
];
parent::init();

View File

@ -0,0 +1,95 @@
<?php
namespace App\Test\TestCase\Controller\Component;
use App\Controller\Component\GradidoNumberComponent;
use Cake\Controller\ComponentRegistry;
use Cake\TestSuite\TestCase;
/**
* App\Controller\Component\NumberComponent Test Case
*/
class GradidoNumberComponentTest extends TestCase
{
/**
* Test subject
*
* @var \App\Controller\Component\NumberComponent
*/
public $GradidoNumberComponent;
/**
* setUp method
*
* @return void
*/
public function setUp()
{
parent::setUp();
$registry = new ComponentRegistry();
$this->GradidoNumberComponent = new GradidoNumberComponent($registry);
}
/**
* tearDown method
*
* @return void
*/
public function tearDown()
{
unset($this->GradidoNumberComponent);
parent::tearDown();
}
/**
* Test parseInputNumberToCentNumber method
*
* @return void
*/
/* public function testParseInputNumberToCentNumber()
{
$this->markTestIncomplete('Not implemented yet.');
}*/
public function test100()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber(100);
$this->assertEquals(1000000, $result);
}
public function test1000()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber(1000);
$this->assertEquals(10000000, $result);
}
public function test100Comma()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber('100,12');
$this->assertEquals(1001200, $result);
}
public function test100Point()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber('100.12');
$this->assertEquals(1001200, $result);
}
public function test100Decimal()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber(100.12);
$this->assertEquals(1001200, $result);
}
public function test1000Point()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber('1000.12');
$this->assertEquals(10001200, $result);
}
public function test1000Comma()
{
$result = $this->GradidoNumberComponent->parseInputNumberToCentNumber('1000,12');
$this->assertEquals(10001200, $result);
}
}

View File

@ -30,7 +30,9 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
];
public $transactions = [
'valid' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3',
'validCreation' => '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'
];
@ -72,7 +74,7 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
public function testNotSetMethod()
{
$this->postAndParse(
['transaction' => $this->transactions['valid']],
['transaction' => $this->transactions['validCreation']],
['state' => 'error', 'msg' => 'parameter error']
);
}
@ -81,7 +83,7 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
{
//$this->post('/TransactionJsonRequestHandler', ['method' => 'putTransaction', 'transaction' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3/cHHaWchkUhWiGhQjB23xCg2pMBELWJ7ZYK']);
$this->postAndParse(
['method' => 'foobar', 'transaction' => $this->transactions['valid']],
['method' => 'foobar', 'transaction' => $this->transactions['validCreation']],
['state' => 'error', 'msg' => 'unknown method', 'details' => 'foobar']
);
@ -92,7 +94,7 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['notBase64']],
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
['Transaction' => 'base64 decode error']
['Transaction' => 'invalid base64 string']
]]
);
}
@ -107,17 +109,26 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
);
}
/**
* Test index method
*
* @return void
*/
public function testIndex()
public function testToLargeCreationSum()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['valid']],
$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 testValidTransaction()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
['state' => 'success']
);
}
@ -139,7 +150,9 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
$json = json_decode($responseBodyString);
$this->assertNotFalse($json);
$expected = json_encode($expected);
if(is_array($expected)) {
$expected = json_encode($expected);
}
$this->assertEquals($expected, $responseBodyString);
}
}