diff --git a/composer.json b/composer.json
index 784c6d123..6a5700b0d 100644
--- a/composer.json
+++ b/composer.json
@@ -6,7 +6,7 @@
"license": "MIT",
"require": {
"php": ">=5.6",
- "cakephp/cakephp": "3.8.*",
+ "cakephp/cakephp": "3.9.*",
"cakephp/migrations": "^2.0.0",
"cakephp/plugin-installer": "^1.0",
"datto/json-rpc": "^6.0",
diff --git a/config/routes.php b/config/routes.php
index 3400992ac..f92b66b8b 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -110,8 +110,10 @@ Router::scope('/', function (RouteBuilder $routes) {
*/
//$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('/', ['controller' => 'Dashboard', 'action' => 'index']);
- $routes->connect('/client', ['controller' => 'Pages', 'action' => 'display', 'js']);
+ //$routes->connect('/client', ['controller' => 'Pages', 'action' => 'display', 'js']);
$routes->connect('/server', ['controller' => 'Dashboard', 'action' => 'serverIndex']);
+ $routes->connect('/client', ['controller' => 'Pages', 'action' => 'display', 'vue']);
+ $routes->connect('/vue-dev', ['controller' => 'Pages', 'action' => 'display', 'vue-dev']);
//$routes->connect('/', 'https://gradido2.dario-rekowski.de/account', array('status' => 303));
/**
diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php
index 729cd88b0..41ce0ff6a 100644
--- a/src/Controller/AppController.php
+++ b/src/Controller/AppController.php
@@ -207,7 +207,10 @@ class AppController extends Controller
$stateUserQuery = $stateUserTable
->find('all')
->where(['public_key' => $public_key_bin])
- ->contain(['StateBalances']);
+ ->contain('StateBalances', function ($q) {
+ return $q->order(['record_date' => 'DESC'])
+ ->limit(1);
+ });
if ($stateUserQuery->count() == 1) {
$stateUser = $stateUserQuery->first();
if ($stateUser->first_name != $json['user']['first_name'] ||
@@ -228,6 +231,7 @@ class AppController extends Controller
}
//var_dump($stateUser);
if (count($stateUser->state_balances) > 0) {
+
$session->write('StateUser.balance', $stateUser->state_balances[0]->decay);
}
$session->write('StateUser.id', $stateUser->id);
diff --git a/src/Controller/JsonRequestHandlerController.php b/src/Controller/JsonRequestHandlerController.php
index 90150f16e..6fef9451b 100644
--- a/src/Controller/JsonRequestHandlerController.php
+++ b/src/Controller/JsonRequestHandlerController.php
@@ -62,12 +62,35 @@ class JsonRequestHandlerController extends AppController {
case 'getUserBalance': return $this->getUserBalance($jsonData->email, $jsonData->last_name);
case 'errorInTransaction': return $this->errorInTransaction($jsonData);
case 'updateReadNode': return $this->updateReadNode();
+ case 'addUser' : return $this->addUser($jsonData->user);
}
return $this->returnJson(['state' => 'error', 'msg' => 'unknown method for post', 'details' => $method]);
}
return $this->returnJson(['state' => 'error', 'msg' => 'no post or get']);
}
+ private function addUser($newUser)
+ {
+ $stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers');
+ $entity = $stateUsersTable->newEntity();
+ $required_fields = ['first_name', 'last_name', 'email', 'public_key', 'disabled'];
+ foreach($required_fields as $required_field) {
+ if(!isset($newUser->$required_field)) {
+ return $this->returnJson(['state' => 'error', 'msg' => 'missing required field in addUser', 'details' => $required_field]);
+ }
+ if('public_key' == $required_field) {
+ $entity->$required_field = hex2bin($newUser->public_hex);
+ } else {
+ $entity->$required_field = $newUser->$required_field;
+ }
+ }
+ if($stateUsersTable->save($entity)) {
+ return $this->returnJson(['state' => 'success']);
+ } else {
+ return $this->returnJson(['state' => 'error', 'msg' => 'error saving state_user', 'details' => $entity->getErrors()]);
+ }
+ }
+
// Called from login server like a cron job every 10 minutes or after sending transaction to hedera
private function updateReadNode()
{
diff --git a/src/Controller/PagesController.php b/src/Controller/PagesController.php
index 87ecc569f..69f57356b 100644
--- a/src/Controller/PagesController.php
+++ b/src/Controller/PagesController.php
@@ -62,14 +62,17 @@ class PagesController extends AppController
if (!empty($path[1])) {
$subpage = $path[1];
}
- $session = $this->getRequest()->getSession();
+ /*$session = $this->getRequest()->getSession();
$result = $this->requestLogin();
if($result !== true) {
return $result;
}
$user = $session->read('StateUser');
- $login_server_session = $this->request->getCookie('GRADIDO_LOGIN', '');
- $this->set(compact('page', 'subpage', 'user', 'login_server_session'));
+ $login_server_session = $this->request->getCookie('GRADIDO_LOGIN', '');*/
+ if($page == "vue" || $page == "vue-dev") {
+ $this->viewBuilder()->setLayout(false);
+ }
+ $this->set(compact('page', 'subpage'));
try {
$this->render(implode('/', $path));
diff --git a/src/Controller/StateBalancesController.php b/src/Controller/StateBalancesController.php
index c87a3032b..435a9329f 100644
--- a/src/Controller/StateBalancesController.php
+++ b/src/Controller/StateBalancesController.php
@@ -250,13 +250,16 @@ class StateBalancesController extends AppController
$current_state_balance->record_date = $date;
}
- echo "amount: ". ($current_state_balance->amount / 10000) . ", duration: " . $current_state_balance->decayDuration(Time::now()) . "
";
- array_push($transactions_reversed, [
- 'type' => 'decay',
- 'balance' => -($current_state_balance->amount - $current_state_balance->decay),
- 'decay_duration' => $current_state_balance->record_date->timeAgoInWords(),// $current_state_balance->decayDuration(Time::now()),
- 'memo' => ''
- ]);
+ if($current_state_balance) {
+ echo "amount: ". ($current_state_balance->amount / 10000) . ", duration: " . $current_state_balance->decayDuration(Time::now()) . "
";
+
+ array_push($transactions_reversed, [
+ 'type' => 'decay',
+ 'balance' => -($current_state_balance->amount - $current_state_balance->decay),
+ 'decay_duration' => $current_state_balance->record_date->timeAgoInWords(),// $current_state_balance->decayDuration(Time::now()),
+ 'memo' => ''
+ ]);
+ }
$this->set('transactions', array_reverse($transactions_reversed));
$this->set('transactionExecutingCount', $session->read('Transaction.executing'));
diff --git a/src/Model/Table/StateBalancesTable.php b/src/Model/Table/StateBalancesTable.php
index 64606e941..cae6e0fe8 100644
--- a/src/Model/Table/StateBalancesTable.php
+++ b/src/Model/Table/StateBalancesTable.php
@@ -82,14 +82,17 @@ class StateBalancesTable extends Table
return $rules;
}
-
+ /*
+ * create new state balance at beginning of next month from $previousStateBalance
+ * calculate decay for the time diff
+ */
private function calculateStateBalance($previousStateBalance)
{
$entity = $this->newEntity();
$entity->state_user_id = $previousStateBalance->state_user_id;
$newDate = $previousStateBalance->record_date;
$newDate->day(1);
- if($newDate->month > 12) {
+ if($newDate->month <= 12) {
$newDate->month($newDate->month + 1);
} else {
$newDate->month(1);
@@ -103,16 +106,113 @@ class StateBalancesTable extends Table
return ['state' => 'error', 'msg' => 'couldn\'t save', 'details' => $entity->getErrors()];
}
- // getting start balance for month, if exist else create and create all missing state_balances before, in while loop
- public function chooseForMonthAndUser($month, $year, $state_user_id)
+ public function sortTransactions($a, $b)
+ {
+ if ($a['date'] == $b['date']) {
+ return 0;
+ }
+ return ($a['date'] > $b['date']) ? -1 : 1;
+ }
+ /*
+ * calculate balance at end of month
+ * work only if state balance at begin of month exist
+ * use transaction_send_coins and transaction_creations
+ */
+ public function updateLastStateBalanceOfMonth($month, $year, $state_user_id)
{
- //'created' => 'identifier'
-
$first_of_month = new Time("$year-$month-01 00:00");
$last_of_month = new Time($first_of_month);
$last_of_month->addMonth(1);
$last_of_month->subSecond(1);
- echo "first of month: " . $first_of_month->i18nFormat() . ", last of month: " . $last_of_month->i18nFormat() . "
";
+ $query = $this->find('all')
+ ->where(['AND' => [
+ 'state_user_id' => $state_user_id,
+ 'record_date >=' => $first_of_month,
+ 'record_date <=' => $last_of_month
+ ]])
+ ->order(['record_date' => 'ASC']);
+ if($query->isEmpty()) {
+ return [
+ 'state' => 'error',
+ 'msg' => 'no state balance in this month found',
+ 'details' => [
+ 'month' => $month,
+ 'year' => $year,
+ 'state_user_id' => $state_user_id
+ ]
+ ];
+ }
+ // get transactions from this month
+ $balance_changes = [];
+ $transactionCreationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
+ $transactionTransfersTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
+ $relevant_creations = $transactionCreationsTable
+ ->find('all')
+ ->where(['AND' => [
+ 'state_user_id' => $state_user_id,
+ 'target_date >=' => $first_of_month,
+ 'target_date <=' => $last_of_month
+ ]])->contain(false);
+ foreach($relevant_creations as $creation) {
+ $balance_changes[] = ['amount' => $creation->amount, 'date' => $creation->target_date];
+ }
+ $relevant_transfers = $transactionTransfersTable
+ ->find('all')
+ ->where(['AND' => [
+ 'OR' => [
+ 'state_user_id' => $state_user_id,
+ 'receiver_user_id' => $state_user_id
+ ],
+ 'transaction.received >= ' => $first_of_month,
+ 'transaction.received <=' => $last_of_month
+ ]])->contain(['Transactions']);
+ debug($relevant_transfers);
+ foreach($relevant_transfers as $transfer) {
+ $amount = $transfer->amount;
+ // if it is a send transaction, negate the value
+ if($transfer->state_user_id == $state_user_id) {
+ $amount *= -1.0;
+ }
+ $balance_changes[] = ['amount' => $amount, 'date' => $transfer->transaction->received];
+ }
+ uasort($balance_changes, array($this, 'sortTransactions'));
+ $current_state_balance = null;
+ if($query->count() == 1) {
+ $current_state_balance = $this->newEntity();
+ $current_state_balance->amount = $query->first()->amount;
+ $current_state_balance->state_user_id = $state_user_id;
+ $current_state_balance->record_date = $query->first()->record_date;
+ } else if($query->count() == 2) {
+ $array = $query->toArray();
+ $current_state_balance = $array[1];
+ } else {
+ throw new Exception('Should\'n occure, never');
+ }
+
+ foreach($balance_changes as $change) {
+ $current_state_balance->amount = $current_state_balance->getDecay($change['date']);
+ $current_state_balance->amount += $change['amount'];
+ $current_state_balance->record_date = $change['date'];
+ }
+ if(!$this->save($current_state_balance)) {
+ return ['state' => 'error', 'msg' => 'couldn\'t save', 'details' => $current_state_balance->getErrors()];
+ }
+ return $current_state_balance;
+ }
+
+ /*
+ * getting start balance for month
+ * create and create all missing state_balances before if not exist
+ * in while loop
+ */
+
+ public function chooseForMonthAndUser($month, $year, $state_user_id)
+ {
+ $first_of_month = new Time("$year-$month-01 00:00");
+ $last_of_month = new Time($first_of_month);
+ $last_of_month->addMonth(1);
+ $last_of_month->subSecond(1);
+ //echo "first of month: " . $first_of_month->i18nFormat() . ", last of month: " . $last_of_month->i18nFormat() . "
";
$query = $this->find('all');
$query->select([
@@ -127,6 +227,7 @@ class StateBalancesTable extends Table
]
])
->order(['record_date' => 'ASC'])
+ ->limit(1)
->contain([]);
if($query->count() == 0)
{
@@ -136,24 +237,8 @@ class StateBalancesTable extends Table
->limit(1)
->order(['record_date' => 'DESC'])
;
- if($state_balances->count() == 1)
- {
- $current_state_balance = $state_balances->first();
- while(true)
- {
- $new_state_balance = $this->calculateStateBalance($current_state_balance);
- if(is_array($new_state_balance)) {
- return ['state' => 'error', 'msg' => 'error calculate state balance', 'details' => $new_state_balance];
- }
- $record_date = $new_state_balance->record_date;
- if($record_date->month === $month && $record_date->year === $year) {
- return $new_state_balance;
- }
- $current_state_balance = $new_state_balance;
- }
- }
- // else create one for first user transaction
- else
+ // create one for first user transaction
+ if($state_balances->isEmpty())
{
$state_user_transactions_table = TableRegistry::getTableLocator()->get('StateUserTransactions');
$state_user_transaction = $state_user_transactions_table->find('all')
@@ -179,13 +264,89 @@ class StateBalancesTable extends Table
}
if(!$this->save($entity)) {
return ['state' => 'error', 'msg' => 'error by saving state balance', 'details' => $entity->getErrors()];
- } else {
- return $entity;
}
}
-
-
+ $state_balances = $this->find('all')
+ ->where(['state_user_id' => $state_user_id])
+ ->limit(1)
+ ->order(['record_date' => 'DESC'])
+ ;
+ if($state_balances->count() == 1)
+ {
+ $current_state_balance = $state_balances->first();
+ while(true)
+ {
+ $new_state_balance_begin = $this->calculateStateBalance($current_state_balance);
+ if(is_array($new_state_balance_begin)) {
+ return ['state' => 'error', 'msg' => 'error calculate state balance', 'details' => $new_state_balance_begin];
+ }
+ $record_date = $new_state_balance_begin->record_date;
+ if($record_date->month === $month && $record_date->year === $year) {
+ return $new_state_balance_begin;
+ }
+ $current_state_balance = $this->updateLastStateBalanceOfMonth($month, $year, $state_user_id);
+ }
+ }
+ else
+ {
+ return ['state' => 'error', 'msg' => 'creation of first state_balance failes'];
+ }
}
return $query->first();
}
+
+ public function updateBalanceWithTransaction($newBalance, $recordDate, $userId)
+ {
+ // max 2 StateBalance Entrys per month:
+ // 1. first of month or first transaction of user
+ // 2. last of month or last transaction of user
+ $first_state_balance_of_month = $this->chooseForMonthAndUser($recordDate->month, $recordDate->year, $userId);
+ $updated_state_balance = null;
+
+ if($first_state_balance_of_month == null || is_array($first_state_balance_of_month)) {
+ return $first_state_balance_of_month;
+ }
+
+ if($first_state_balance_of_month->record_date->day == $recordDate->day &&
+ $recordDate > $first_state_balance_of_month->record_date) {
+ if($first_state_balance_of_month->amount == $newBalance) {
+ // nothing to do here
+ return true;
+ }
+ $updated_state_balance = $first_state_balance_of_month;
+ $updated_state_balance->amount = $newBalance;
+ // copy complete record date, inclusive time
+ $first_state_balance_of_month->record_date = $recordDate;
+ } else {
+ $query = $this->find('all')
+ ->where(['AND' => [
+ 'record_date >' => $first_state_balance_of_month->record_date,
+ 'record_date <=' => $recordDate,
+ 'state_user_id' => $userId
+ ]]);
+ if(!$query->isEmpty()) {
+ $updated_state_balance = $query->first();
+ if($updated_state_balance->record_date == $recordDate) {
+ return true;
+ }
+ } else {
+ $updated_state_balance = $this->newEntity();
+ $updated_state_balance->state_user_id = $userId;
+ }
+ $updated_state_balance->record_date = $recordDate;
+ $updated_state_balance->amount = $newBalance;
+ }
+
+ if($updated_state_balance) {
+ if(!$this->save($updated_state_balance)) {
+ return ['state' => 'error', 'msg' => 'error by saving state balance', 'details' => $entity->getErrors()];
+ }
+
+ // delete all state_balances which came after
+ // they will be automaticlly recovered by next call of chooseForMonthAndUser
+ $this->deleteAll(['state_user_id' => $userId, 'record_date >' => $recordDate]);
+ }
+
+ return true;
+ }
}
diff --git a/src/Model/Transactions/Record.php b/src/Model/Transactions/Record.php
index ac378d56c..686994137 100644
--- a/src/Model/Transactions/Record.php
+++ b/src/Model/Transactions/Record.php
@@ -77,13 +77,22 @@ class GradidoModifieUserBalance
public function updateBalance($newBalance, $recordDate, $userId)
{
+
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
- $stateBalanceQuery = $stateBalancesTable->find('all')->where(['state_user_id' => $userId]);
+ return $stateBalancesTable->updateBalanceWithTransaction($newBalance, $recordDate, $userId);
+
+ /*$first_of_month = new Time("$year-$month-01 00:00");
+ $stateBalanceQuery = $stateBalancesTable
+ ->find('all')
+ ->where(['state_user_id' => $userId])
+ ->order(['record_date' => 'DESC'])
+ ->limit(1);
$entity = null;
if(!$stateBalanceQuery->isEmpty()) {
$entity = $stateBalanceQuery->first();
- if($entity->record_date != NULL && $entity->record_date > $recordDate) {
+ if($entity->record_date != NULL &&
+ ($entity->record_date > $recordDate || $entity->record_date->day == 1)) {
return false;
}
} else {
@@ -95,7 +104,7 @@ class GradidoModifieUserBalance
/*if(!$stateBalancesTable->save($entity)) {
return ['state' => 'error', 'msg' => 'error saving state balance', 'details' => $entity->getErrors()];
}*/
- return true;
+ //return true;
}
public function getAllStateUsers()
@@ -209,8 +218,8 @@ class GradidoCreation extends GradidoModifieUserBalance
public function __construct($data)
{
$this->userPubkey = $data['user'];
- $this->amount = $data['amount'];
- $this->new_balance = $data['new_balance'];
+ $this->amount = $data['amount']['amount'];
+ $this->new_balance = $data['new_balance']['amount'];
//$this->targetDate = $received;
}
@@ -276,15 +285,15 @@ class GradidoTransfer extends GradidoModifieUserBalance
public function __construct($data)
{
- $this->amount = $data['amount'];
+ $this->amount = $data['amount']['amount'];
$sender = $data['sender'];
$this->sender_pubkey = $sender['user'];
- $this->sender_new_balance = $sender['new_balance'];
+ $this->sender_new_balance = $sender['new_balance']['amount'];
$receiver = $data['receiver'];
$this->receiver_pubkey = $receiver['user'];
- $this->receiver_new_balance = $receiver['new_balance'];
+ $this->receiver_new_balance = $receiver['new_balance']['amount'];
}
diff --git a/src/Template/Pages/js.ctp b/src/Template/Pages/js.ctp
index bb3167acf..60868adc4 100644
--- a/src/Template/Pages/js.ctp
+++ b/src/Template/Pages/js.ctp
@@ -1,14 +1,41 @@
-layout = false;?>
-