redesign state balances overview

This commit is contained in:
Dario Rekowski on RockPI 2019-11-27 11:17:48 +00:00
parent 0f5fb4575b
commit af758d1d0e
34 changed files with 9384 additions and 14 deletions

View File

@ -2,8 +2,8 @@
namespace App\Controller;
use App\Controller\AppController;
use Cake\Routing\Router;
use Cake\ORM\TableRegistry;
//use Cake\Routing\Router;
//use Cake\ORM\TableRegistry;
/**
* StateUsers Controller

View File

@ -1,6 +1,7 @@
<?php
namespace App\Controller;
use Cake\ORM\TableRegistry;
use App\Controller\AppController;
/**
@ -37,7 +38,35 @@ class StateBalancesController extends AppController
public function overview()
{
$startTime = microtime(true);
$this->viewBuilder()->setLayout('frontend');
$this->viewBuilder()->setLayout('frontend_ripple');
$session = $this->getRequest()->getSession();
$user = $session->read('StateUser');
// var_dump($user);
if(!$user) {
//return $this->redirect(Router::url('/', true) . 'account/', 303);
$result = $this->requestLogin();
if($result !== true) {
return $result;
}
$user = $session->read('StateUser');
}
$creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
$creationTransactions = $creationsTable
->find('all')
->where(['state_user_id' => $user['id']])
->contain(['Transactions']);
$transferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
$transferTransactions = $transferTable
->find('all')
->where(['OR' => ['state_user_id' => $user['id'], 'receiver_user_id' => $user['id']]])
->contain(['Transactions']);
$transactions = [];
foreach($creationTransactions as $creation) {
}
$this->set('timeUsed', microtime(true) - $startTime);
}

View File

@ -92,6 +92,11 @@ class TransactionSendCoinsController extends AppController
$receiverUsers = $this->TransactionSendCoins->ReceiverUsers->find('list', ['limit' => 200]);
$this->set(compact('transactionSendCoin', 'transactions', 'stateUsers', 'receiverUsers'));
}
public function create()
{
}
/**
* Delete method

View File

@ -61,6 +61,10 @@ class StateUsersTable extends Table
$this->hasMany('TransactionSendCoins', [
'foreignKey' => 'state_user_id'
]);
$this->hasMany('TransactionReceiveCoins', [
'className' => 'TransactionSendCoins',
'foreignKey' => 'receiver_user_id'
]);
}
/**
@ -96,4 +100,19 @@ class StateUsersTable extends Table
return $rules;
}
public function getReceiverProposal() {
$stateUsers = $this->find('all');
$receiverProposal = [];
foreach($stateUsers as $stateUser) {
$name = $stateUser->email;
$keyHex = bin2hex(stream_get_contents($stateUser->public_key));
if($name === NULL) {
$name = $stateUser->first_name . ' ' . $stateUser->last_name;
}
array_push($receiverProposal, ['name' => $name, 'key' => $keyHex]);
//$stateUser->public_key
}
return $receiverProposal;
}
}

View File

@ -45,6 +45,10 @@ class TransactionCreationsTable extends Table
'foreignKey' => 'state_user_id',
'joinType' => 'INNER'
]);
$this->belongsTo('StateUsers', [
'foreignKey' => 'receiver_user_id',
'joinType' => 'INNER'
]);
}
/**
@ -82,6 +86,7 @@ class TransactionCreationsTable extends Table
{
$rules->add($rules->existsIn(['transaction_id'], 'Transactions'));
$rules->add($rules->existsIn(['state_user_id'], 'StateUsers'));
$rules->add($rules->existsIn(['receiver_user_id'], 'StateUsers'));
return $rules;
}

View File

@ -101,7 +101,7 @@ class Transaction extends TransactionBase {
$connection->begin();
//id transaction_id signature pubkey
if (!$this->mTransactionBody->save($this->getFirstPublic())) {
if (!$this->mTransactionBody->save($this->getFirstPublic(), $this->mProtoTransaction->getSigMap())) {
$this->addErrors($this->mTransactionBody->getErrors());
$connection->rollback();
return false;
@ -117,7 +117,6 @@ class Transaction extends TransactionBase {
$signatureEntitys = [];
foreach($sigPairs as $sigPair) {
$signatureEntity = $transactionsSignaturesTable->newEntity();
$signatureEntity->transaction_id = $transactionId;
$signatureEntity->signature = $sigPair->getEd25519();
$signatureEntity->pubkey = $sigPair->getPubKey();
@ -136,6 +135,8 @@ class Transaction extends TransactionBase {
return false;
}
$connection->commit();
return true;
}

View File

@ -51,7 +51,7 @@ class TransactionBase {
//debug($stateBalanceQuery);
if($stateBalanceQuery->count() > 0) {
$stateBalanceEntry = $stateBalanceEntry->first();
$stateBalanceEntry = $stateBalanceQuery->first();
$stateBalanceEntry->amount += $newAmountCent;
} else {
$stateBalanceEntry = $stateBalancesTable->newEntity();

View File

@ -68,7 +68,7 @@ class TransactionBody extends TransactionBase {
return $this->mProtoTransactionBody->getData();
}
public function save($firstPublic) {
public function save($firstPublic, $sigMap) {
$transactionsTable = TableRegistry::getTableLocator()->get('transactions');
$transactionEntity = $transactionsTable->newEntity();
@ -87,7 +87,45 @@ class TransactionBody extends TransactionBase {
$this->addError('TransactionBody::save', 'error saving transaction with: ' . json_encode($transactionEntity->getError()));
return false;
}
return true;
$previousTxHash = null;
if($this->mTransactionID > 1) {
try {
$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;
}
if(!$previousTransaction) {
// shouldn't occur
$this->addError('TransactionBody::save', 'previous transaction (with id ' . ($this->mTransactionID-1) . ' not found');
return false;
}
$previousTxHash = $previousTransaction->tx_hash;
}
$transactionEntity->received = $transactionsTable->get($transactionEntity->id, ['contain' => false, 'fields' => ['received']])->received;
// calculate tx hash
// previous tx hash + id + received + sigMap as string
// Sodium use for the generichash function BLAKE2b today (11.11.2019), mabye change in the future
$state = \Sodium\crypto_generichash_init();
//echo "prev hash: $previousTxHash\n";
if($previousTxHash != null) {
\Sodium\crypto_generichash_update($state, stream_get_contents($previousTxHash));
}
//echo "id: " . $transactionEntity->id . "\n";
\Sodium\crypto_generichash_update($state, strval($transactionEntity->id));
//echo "received: " . $transactionEntity->received;
\Sodium\crypto_generichash_update($state, $transactionEntity->received->i18nFormat('yyyy-MM-dd HH:mm:ss'));
\Sodium\crypto_generichash_update($state, $sigMap->serializeToString());
$transactionEntity->tx_hash = \Sodium\crypto_generichash_final($state);
if ($transactionsTable->save($transactionEntity)) {
return true;
}
$this->addError('TransactionBody::save', 'error saving transaction with: ' . json_encode($transactionEntity->getError()));
return false;
}
public function getTransactionID() {

View File

@ -73,12 +73,13 @@ class TransactionCreation extends TransactionBase {
$transactionCreationEntity->transaction_id = $transaction_id;
// state user id
$state_user_id = $this->getStateUserId($firstPublic);
if(!$state_user_id) {
//$state_user_id = $this->getStateUserId($firstPublic);
$receiverUser = $this->getStateUserId($this->getReceiverPublic());
if(!$receiverUser) {
$this->addError('TransactionCreation::save', 'couldn\'t get state user id');
return false;
}
$transactionCreationEntity->state_user_id = $state_user_id;
$transactionCreationEntity->state_user_id = $receiverUser;
$transactionCreationEntity->amount = $this->getAmount();
$transactionCreationEntity->ident_hash = $this->getIdentHash();
@ -86,7 +87,7 @@ 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;

View File

@ -1,6 +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)
@ -50,7 +50,7 @@ if(!isset($balance)) {
<body>
<div class="versionstring dev-info">
<p class="grd_small">Community Server in Entwicklung</p>
<p class="grd_small">Alpha 0.5.0</p>
<p class="grd_small">Alpha 0.6.0</p>
</div>
<nav class="grd-left-bar expanded" data-topbar role="navigation">
<div class="grd-left-bar-section">

View File

@ -0,0 +1,130 @@
<?php
use Cake\Routing\Router;
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 0.10.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
$cakeDescription = 'Gradido';
//echo "balance: $balance<br>";
//echo "transactions pending: " . $transactionPendings;
?>
<!DOCTYPE html>
<html>
<head>
<?= $this->Html->charset() ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
<?= $cakeDescription ?>:
<?= $this->fetch('title') ?>
</title>
<?= $this->Html->meta('icon') ?>
<?= $this->Html->css(['rippleUI/style.css', 'materialdesignicons.min.css']) ?>
<?= $this->Html->script(['basic']) ?>
<?= $this->fetch('meta') ?>
<?= $this->fetch('css') ?>
<?= $this->fetch('script') ?>
</head>
<body class="header-fixed">
<div class="versionstring dev-info">
<p class="grd_small"><?= __("Community Server in Entwicklung") ?></p>
<p class="grd_small">Alpha 0.8.0</p>
</div>
<nav class="t-header">
<div class="t-header-brand-wrapper">
<a href="/">
<?= $this->Html->image('logo_schrift_half.webp', ['alt' => 'Logo', 'class' => 'logo']) ?>
<?= $this->Html->image('logo_half.webp', ['alt' => 'Logo', 'class' => 'logo-mini']) ?>
</a>
<button class="t-header-toggler t-header-desk-toggler d-none d-lg-block">
<svg class="logo" viewBox="0 0 200 200">
<path class="top" d="
M 40, 80
C 40, 80 120, 80 140, 80
C180, 80 180, 20 90, 80
C 60,100 30,120 30,120
"></path>
<path class="middle" d="
M 40,100
L140,100
"></path>
<path class="bottom" d="
M 40,120
C 40,120 120,120 140,120
C180,120 180,180 90,120
C 60,100 30, 80 30, 80
"></path>
</svg>
</button>
</div>
<div class="t-header-content-wrapper">
<div class="t-header-content">
<button class="t-header-toggler t-header-mobile-toggler d-block d-lg-none">
<i class="mdi mdi-menu"></i>
</button>
<div class="flash-messages" style="margin-left:20px; margin-top:30px;">
<?= $this->Flash->render() ?>
</div>
</div>
</div>
</nav>
<div class="page-body">
<!-- partial:partials/_sidebar.html -->
<div class="sidebar">
<?= $this->element('navi'); ?>
</div>
<div class="page-content-wrapper">
<div class="page-content-wrapper-inner">
<div class="viewport-header">
<nav aria-label="breadcrumb">
<ol class="breadcrumb has-arrow">
<li class="breadcrumb-item">
<a href="index.html">Startseite</a>
</li>
<li class="breadcrumb-item active" aria-current="page"><?= $this->fetch('title') ?></li>
</ol>
</nav>
</div>
<div class="content-viewport">
<?= $this->fetch('content') ?>
</div>
</div>
<!-- content viewport ends -->
<!-- partial:partials/_footer.html -->
<footer class="footer">
<div class="row">
<div class="col-sm-6 text-center text-sm-right order-sm-1">
<ul class="text-gray">
<li><a href="#">Terms of use</a></li>
<li><a href="#">Privacy Policy</a></li>
</ul>
</div>
<div class="col-sm-6 text-center text-sm-left mt-3 mt-sm-0">
<small class="text-muted d-block">Copyright © 2019 Gradido</small>
</div>
</div>
</footer>
<!-- partial -->
</div>
<!-- page content ends -->
</div>
<?php if(isset($timeUsed)) : ?>
<div class="grd-time-used dev-info">
<?= round($timeUsed * 1000.0, 4) ?> ms
</div>
<?php endif; ?>
</body>
</html>

View File

@ -6,3 +6,88 @@
* and open the template in the editor.
*/
$this->assign('title', __('Kontoübersicht'));
?>
<div class="row">
<div class="col-md-10 equel-grid">
<div class="grid">
<div class="grid-body py-3">
<p class="card-title ml-n1">Überweisungen</p>
</div>
<div class="table-responsive">
<table class="table table-hover table-sm">
<thead>
<tr class="solid-header">
<th colspan="2" class="pl-4">Absender</th>
<th>Transaktions Nr.</th>
<th>Datum</th>
<th>Betrag</th>
</tr>
</thead>
<tbody>
<tr>
<td class="pr-0 pl-4">
<?= $this->Html->image('50x50.png', ['class' => 'profile-img img-sm', 'alt' => 'profile image']) ?>
</td>
<td class="pl-md-0">
<small class="text-black font-weight-medium d-block">Barbara Curtis</small>
<span>
<span class="status-indicator rounded-indicator small bg-primary"></span>Account Deactivated </span>
</td>
<td>
<small>8523537435</small>
</td>
<td> Just Now </td>
<td>120</td>
</tr>
<tr>
<td class="pr-0 pl-4">
<?= $this->Html->image('50x50.png', ['class' => 'profile-img img-sm', 'alt' => 'profile image']) ?>
</td>
<td class="pl-md-0">
<small class="text-black font-weight-medium d-block">Charlie Hawkins</small>
<span>
<span class="status-indicator rounded-indicator small bg-success"></span>Email Verified </span>
</td>
<td>
<small>9537537436</small>
</td>
<td> Mar 04, 2018 11:37am </td>
<td>-120</td>
</tr>
<tr>
<td class="pr-0 pl-4">
<?= $this->Html->image('50x50.png', ['class' => 'profile-img img-sm', 'alt' => 'profile image']) ?>
</td>
<td class="pl-md-0">
<small class="text-black font-weight-medium d-block">Nina Bates</small>
<span>
<span class="status-indicator rounded-indicator small bg-warning"></span>Payment On Hold </span>
</td>
<td>
<small>7533567437</small>
</td>
<td> Mar 13, 2018 9:41am </td>
<td>10</td>
</tr>
<tr>
<td class="pr-0 pl-4">
<?= $this->Html->image('50x50.png', ['class' => 'profile-img img-sm', 'alt' => 'profile image']) ?>
</td>
<td class="pl-md-0">
<small class="text-black font-weight-medium d-block">Hester Richards</small>
<span>
<span class="status-indicator rounded-indicator small bg-success"></span>Email Verified </span>
</td>
<td>
<small>5673467743</small>
</td>
<td> Feb 21, 2018 8:34am </td>
<td>500</td>
</tr>
</tbody>
</table>
</div>
<a class="border-top px-3 py-2 d-block text-gray" href="#"><small class="font-weight-medium"><i class="mdi mdi-chevron-down mr-2"></i>View All Order History</small></a>
</div>
</div>
</div>

View File

@ -17,6 +17,7 @@ foreach($receiverProposal as $i => $receiver) {
$this->assign('title', __('Schöpfungstransaktion'));
?>
<div class="grd_container_small">
Funktioniert im Augenblick noch nicht.
<?= $this->Form->create($creationForm) ?>
<fieldset>
<?= $this->Form->control('memo'); ?>

View File

@ -125,6 +125,11 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase
);
}
/*public function testMissingPreviousTransaction()
{
}*/
public function testValidTransaction()
{
$this->postAndParse(

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
webroot/img/50x50.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

BIN
webroot/img/logo_half.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

75
webroot/js/basic.js Normal file
View File

@ -0,0 +1,75 @@
/*
* 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.
*/
// cross browser dom is ready module from:
// https://www.competa.com/blog/cross-browser-document-ready-with-vanilla-javascript/
var domIsReady = (function(domIsReady) {
var isBrowserIeOrNot = function() {
return (!document.attachEvent || typeof document.attachEvent === "undefined" ? 'not-ie' : 'ie');
}
domIsReady = function(callback) {
if(callback && typeof callback === 'function'){
if(isBrowserIeOrNot() !== 'ie') {
document.addEventListener("DOMContentLoaded", function() {
return callback();
});
} else {
document.attachEvent("onreadystatechange", function() {
if(document.readyState === "complete") {
return callback();
}
});
}
} else {
console.error('The callback is not a function!');
}
}
return domIsReady;
})(domIsReady || {});
/*
* var el = document.querySelector('.toggle-me');
el.onclick = function() {
el.classList.toggle('active');
}
*/
// cross browser dom is ready
(function(document, window, domIsReady, undefined) {
domIsReady(function() {
//console.log('My DOM is ready peeps!');
//document.querySelector('#page').style.background = 'blue';
//var Body = $("body");
var DesktopToggler = document.querySelector('.t-header-desk-toggler');
var MobileToggler = document.querySelector('.t-header-mobile-toggler');
var HeaderToggle = document.querySelector('.t-header-toggler');
// SIDEBAR TOGGLE FUNCTION FOR LARGE SCREENS (SCREEN "LG" AND UP)
if(DesktopToggler) {
DesktopToggler.addEventListener('click', function ()
{
//$(Body).toggleClass("sidebar-minimized");
document.body.classList.toggle('sidebar-minimized');
});
}
// SIDEBAR TOGGLE FUNCTION FOR MOBILE (SCREEN "MD" AND DOWN)
if(MobileToggler) {
MobileToggler.addEventListener('click', function () {
document.querySelector('.page-body').classList.toggle('sidebar-collpased');
});
}
if(HeaderToggle) {
HeaderToggle.addEventListener('click', function () {
HeaderToggle.classList.toggle('arrow');
});
}
});
})(document, window, domIsReady);

View File