From be26bf27587b891512067670e5a7ec150fecd61b Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Mon, 10 May 2021 17:59:34 +0000 Subject: [PATCH] tested and fixed bugs, update api docu --- .../gradido_community/transaction_types.sql | 2 +- .../src/Controller/AppController.php | 2 +- .../src/Controller/MigrationsController.php | 18 +++-- .../src/Model/Entity/StateBalance.php | 12 ++-- community_server/src/Model/Table/AppTable.php | 21 +++++- .../src/Model/Table/BlockchainTypesTable.php | 15 ++-- .../src/Model/Table/StateBalancesTable.php | 19 +++++- .../src/Model/Table/TransactionTypesTable.php | 17 ++--- .../src/Model/Table/TransactionsTable.php | 64 ++++++++--------- .../AppRequests/list_transactions.ctp | 3 + .../src/Template/Migrations/migrate.ctp | 2 +- docu/community-server.api.md | 68 +++++++++++++++++-- 12 files changed, 165 insertions(+), 78 deletions(-) diff --git a/community_server/db/skeema/gradido_community/transaction_types.sql b/community_server/db/skeema/gradido_community/transaction_types.sql index a3e6779d9..10aad25b0 100644 --- a/community_server/db/skeema/gradido_community/transaction_types.sql +++ b/community_server/db/skeema/gradido_community/transaction_types.sql @@ -1,6 +1,6 @@ CREATE TABLE `transaction_types` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(90) COLLATE utf8mb4_unicode_ci NOT NULL, `text` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/community_server/src/Controller/AppController.php b/community_server/src/Controller/AppController.php index 80690b238..9f577d77a 100644 --- a/community_server/src/Controller/AppController.php +++ b/community_server/src/Controller/AppController.php @@ -166,7 +166,7 @@ class AppController extends Controller } $php_data_version = 2; if($current_db_version < $php_data_version) { - $this->redirect(['controller' => 'Migrations', 'action' => 'migrate', $html, $current_db_version]); + $this->redirect(['controller' => 'Migrations', 'action' => 'migrate', 'html' => $html, 'db_version' => $current_db_version]); } } diff --git a/community_server/src/Controller/MigrationsController.php b/community_server/src/Controller/MigrationsController.php index ddf02bfdc..31fa41001 100644 --- a/community_server/src/Controller/MigrationsController.php +++ b/community_server/src/Controller/MigrationsController.php @@ -13,6 +13,12 @@ use Cake\ORM\TableRegistry; */ class MigrationsController extends AppController { + public function initialize() + { + parent::initialize(); + $this->Auth->allow('migrate'); + } + /** * Index method * @@ -36,8 +42,12 @@ class MigrationsController extends AppController return ['success' => true]; } - public function migrate($html, $current_db_version) + public function migrate() { + + $html = $this->request->getQuery('html'); + $current_db_version = $this->request->getQuery('db_version'); + $startTime = microtime(true); $stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions'); $transactionsTable = TableRegistry::getTableLocator()->get('Transactions'); @@ -52,10 +62,10 @@ class MigrationsController extends AppController if($current_db_version == 1) { $stateUserTransactionsTable->truncate(); $commands = [ - [$transactionsTable, 'fillStateUserTransactions'], - [$stateBalancesTable, 'updateAllBalances'], [$blockchainTypesTable, 'fillWithDefault'], - [$transactionTypesTable, 'fillWithDefault'] + [$transactionTypesTable, 'fillWithDefault'], + [$transactionsTable, 'fillStateUserTransactions'], + [$stateBalancesTable, 'updateAllBalances'] ]; $new_db_version = 2; } diff --git a/community_server/src/Model/Entity/StateBalance.php b/community_server/src/Model/Entity/StateBalance.php index 7d595653e..334db222f 100644 --- a/community_server/src/Model/Entity/StateBalance.php +++ b/community_server/src/Model/Entity/StateBalance.php @@ -44,9 +44,7 @@ class StateBalance extends Entity } else if(method_exists($dateOrTime, 'i18nFormat')) { return $dateOrTime->i18nFormat(Time::UNIX_TIMESTAMP_FORMAT); } else { - var_dump($dateOrTime); - debug_print_backtrace(0, 6); - die("date or time unexpected object"); + return 0; } } @@ -59,8 +57,12 @@ class StateBalance extends Entity // SELECT TIMESTAMPDIFF(SECOND, modified, CURDATE()) AS age_in_seconds from state_balances // decay_for_duration = decay_factor^seconds // decay = gradido_cent * decay_for_duration - - $decay_duration = intval(Time::now()->getTimestamp() - $this->convertToTimestamp($this->record_date)); + $startDate = $this->convertToTimestamp($this->record_date); + if($startDate == 0) { + return $this->amount; + } + + $decay_duration = intval(Time::now()->getTimestamp() - $startDate); if($decay_duration === 0) { return $this->amount; } diff --git a/community_server/src/Model/Table/AppTable.php b/community_server/src/Model/Table/AppTable.php index 3a281afcc..138a7f949 100644 --- a/community_server/src/Model/Table/AppTable.php +++ b/community_server/src/Model/Table/AppTable.php @@ -1,5 +1,7 @@ schema()->truncateSql($this->connection()); + $truncateCommands = $this->getSchema()->truncateSql($this->getConnection()); foreach ($truncateCommands as $truncateCommand) { - $this->connection()->query($truncateCommand); + $this->getConnection()->query($truncateCommand); } + $this->getConnection()->query('ALTER TABLE ' . $this->getSchema()->name() . ' AUTO_INCREMENT=1'); } + public function saveManyWithErrors($entities) + { + $save_results = $this->saveMany($entities); + // save all at once failed, no try one by one to get error message + if($save_results === false) { + foreach($entities as $entity) { + if(!$this->save($entity)) { + return ['success' => false, 'errors' => $entity->getErrors()]; + } + } + } else { + return ['success' => true]; + } + } } diff --git a/community_server/src/Model/Table/BlockchainTypesTable.php b/community_server/src/Model/Table/BlockchainTypesTable.php index 252fb8fd7..3aa67a83d 100644 --- a/community_server/src/Model/Table/BlockchainTypesTable.php +++ b/community_server/src/Model/Table/BlockchainTypesTable.php @@ -84,18 +84,11 @@ class BlockchainTypesTable extends AppTable ]; $entities = $this->newEntities($entry_contents); $this->truncate(); - $save_results = $this->saveMany($entities); - $errors = []; - foreach($save_results as $i => $result) - { - if(!$result) { - $errors[] = $entities[$i]->getErrors(); - } + $save_results = $this->saveManyWithErrors($entities); + if(!$save_results['success']) { + $save_results['msg'] = 'error by saving default transaction types'; } - if(count($errors) > 0) { - return ['success' => false, 'msg' => 'error by saving blockchain types', 'errors' => $errors]; - } - return ['success' => true]; + return $save_results; } } diff --git a/community_server/src/Model/Table/StateBalancesTable.php b/community_server/src/Model/Table/StateBalancesTable.php index 87e961c5d..8ee3be193 100644 --- a/community_server/src/Model/Table/StateBalancesTable.php +++ b/community_server/src/Model/Table/StateBalancesTable.php @@ -91,25 +91,38 @@ class StateBalancesTable extends Table return $rules; } - public static function calculateDecay($startBalance, FrozenTime $startDate, FrozenTime $endDate) + public function calculateDecay($startBalance, FrozenTime $startDate, FrozenTime $endDate, $withInterval = false) { $decayStartDate = self::getDecayStartDateCached(); // if no start decay block exist, we just return input // if start date for decay is after enddate, we also just return input if($decayStartDate === null || $decayStartDate >= $endDate) { - return $startBalance; + if($withInterval) { + return ['balance' => $startBalance, 'interval' => new \DateInterval('PT0S')]; + } else { + return $startBalance; + } } $state_balance = $this->newEntity(); $state_balance->amount = $startBalance; + $interval = null; // if decay start date is before start date we calculate decay for full duration if($decayStartDate < $startDate) { $state_balance->record_date = $startDate; + $interval = $endDate->diff($startDate); } // if decay start in between start date and end date we caculcate decay from decay start time to end date else { $state_balance->record_date = $decayStartDate; + $interval = $endDate->diff($decayStartDate); } - return $state_balance->partDecay($endDate); + $decay = $state_balance->partDecay($endDate); + if($withInterval) { + return ['balance' => $decay, 'interval' => $interval]; + } else { + return $decay; + } + } diff --git a/community_server/src/Model/Table/TransactionTypesTable.php b/community_server/src/Model/Table/TransactionTypesTable.php index 7669ff2b3..2ffd1e64c 100644 --- a/community_server/src/Model/Table/TransactionTypesTable.php +++ b/community_server/src/Model/Table/TransactionTypesTable.php @@ -55,7 +55,7 @@ class TransactionTypesTable extends AppTable $validator ->scalar('name') - ->maxLength('name', 24) + ->maxLength('name', 45) ->requirePresence('name', 'create') ->notEmptyString('name'); @@ -111,17 +111,10 @@ class TransactionTypesTable extends AppTable ]; $entities = $this->newEntities($entry_contents); $this->truncate(); - $save_results = $this->saveMany($entities); - $errors = []; - foreach($save_results as $i => $result) - { - if(!$result) { - $errors[] = $entities[$i]->getErrors(); - } + $save_results = $this->saveManyWithErrors($entities); + if(!$save_results['success']) { + $save_results['msg'] = 'error by saving default transaction types'; } - if(count($errors) > 0) { - return ['success' => false, 'msg' => 'error by saving transaction types', 'errors' => $errors]; - } - return ['success' => true]; + return $save_results; } } diff --git a/community_server/src/Model/Table/TransactionsTable.php b/community_server/src/Model/Table/TransactionsTable.php index 9ae2fe02a..5169129d7 100644 --- a/community_server/src/Model/Table/TransactionsTable.php +++ b/community_server/src/Model/Table/TransactionsTable.php @@ -1,12 +1,12 @@ 0 && $decay == true) - { + $prev = null; + if($i > 0 ) { $prev = $stateUserTransactions[$i-1]; + } + if($prev && $decay == true) + { + if($prev->balance > 0) { // var_dump($stateUserTransactions); $current = $su_transaction; //echo "decay between " . $prev->transaction_id . " and " . $current->transaction_id . "
"; - $interval = $current->balance_date->diff($prev->balance_date); - $state_balance->amount = $prev->balance; - $state_balance->record_date = $prev->balance_date; - $diff_amount = $state_balance->partDecay($current->balance_date); - + $calculated_decay = $stateBalancesTable->calculateDecay($prev->balance, $prev->balance_date, $current->balance_date, true); + //echo $interval->format('%R%a days'); //echo "prev balance: " . $prev->balance . ", diff_amount: $diff_amount, summe: " . (-intval($prev->balance - $diff_amount)) . "
"; $final_transactions[] = [ 'type' => 'decay', - 'balance' => floatval(intval($prev->balance - $diff_amount)), - 'decay_duration' => $interval->format('%a days, %H hours, %I minutes, %S seconds'), + 'balance' => floatval($prev->balance - $calculated_decay['balance']), + 'decay_duration' => $calculated_decay['interval']->format('%a days, %H hours, %I minutes, %S seconds'), 'memo' => '' ]; } @@ -207,13 +208,16 @@ class TransactionsTable extends Table echo "
";*/ if($su_transaction->transaction_type_id == 1) { // creation $creation = $transaction->transaction_creation; + $balance = $stateBalancesTable->calculateDecay($creation->amount, $creation->target_date, $transaction->received); + $final_transactions[] = [ 'name' => 'Gradido Akademie', 'type' => 'creation', 'transaction_id' => $transaction->id, 'date' => $transaction->received,// $creation->target_date, 'target_date' => $creation->target_date, - 'balance' => $creation->amount, + 'creation_amount' => $creation->amount, + 'balance' => $balance, 'memo' => $transaction->memo ]; } else if($su_transaction->transaction_type_id == 2) { // transfer or send coins @@ -253,12 +257,18 @@ class TransactionsTable extends Table } if($i == $stateUserTransactionsCount-1 && $decay == true) { - $state_balance->amount = $su_transaction->balance; - $state_balance->record_date = $su_transaction->balance_date; + $calculated_decay = $stateBalancesTable->calculateDecay( + $su_transaction->balance, + $su_transaction->balance_date, new FrozenTime(), true); + $decay_start_date = $stateBalancesTable->getDecayStartDateCached(); + $duration = $su_transaction->balance_date->timeAgoInWords(); + if($decay_start_date > $su_transaction->balance_date) { + $duration = $decay_start_date->timeAgoInWords(); + } $final_transactions[] = [ 'type' => 'decay', - 'balance' => floatval(intval($su_transaction->balance - $state_balance->decay)), - 'decay_duration' => $su_transaction->balance_date->timeAgoInWords(), + 'balance' => floatval($su_transaction->balance - $calculated_decay['balance']), + 'decay_duration' => $duration, 'memo' => '' ]; } @@ -337,12 +347,13 @@ class TransactionsTable extends Table } public function fillStateUserTransactions() - { + { $missing_transaction_ids = []; $transaction_ids = $this ->find('all') ->select(['id', 'transaction_type_id']) ->order(['id']) + ->where(['transaction_type_id <' => 6]) ->all() ; $state_user_transaction_ids = $this->StateUserTransactions @@ -422,21 +433,10 @@ class TransactionsTable extends Table } } - $results = $this->StateUserTransactions->saveMany($finalEntities); - $errors = []; - foreach($results as $i => $res) { - if($res == false) { - $errors[] = $finalEntities[$i]->getErrors(); - } + $save_results = $this->StateUserTransactions->saveManyWithErrors($finalEntities); + if(!$save_results['success']) { + $save_results['msg'] = 'error by saving at least one state user transaction'; } - if(count($errors) == 0) { - $result = ['success' => true]; - } else { - $result = ['success' => false, 'msg' => 'error by saving at least one state user transaction', 'errors' => $errors]; - } - - - - return $result; + return $save_results; } } diff --git a/community_server/src/Template/AppRequests/list_transactions.ctp b/community_server/src/Template/AppRequests/list_transactions.ctp index f829b5f16..28a76f2be 100644 --- a/community_server/src/Template/AppRequests/list_transactions.ctp +++ b/community_server/src/Template/AppRequests/list_transactions.ctp @@ -12,6 +12,9 @@ $body['gdtSum'] = $this->element('centToFloat', ['cent' => $body['gdtSum'], 'pre foreach($body['transactions'] as $i => $transaction) { $body['transactions'][$i]['balance'] = $this->element('centToFloat', ['cent' => $transaction['balance'], 'precision' => 4]); + if(isset($transaction['creation_amount'])) { + $body['transactions'][$i]['creation_amount'] = $this->element('centToFloat', ['cent' => $transaction['creation_amount'], 'precision' => 4]); + } } ?> \ No newline at end of file diff --git a/community_server/src/Template/Migrations/migrate.ctp b/community_server/src/Template/Migrations/migrate.ctp index 4c191fb61..d345c9a90 100644 --- a/community_server/src/Template/Migrations/migrate.ctp +++ b/community_server/src/Template/Migrations/migrate.ctp @@ -10,7 +10,7 @@

Migrate from Version

Success

- +

Error

diff --git a/docu/community-server.api.md b/docu/community-server.api.md index 9354bf232..5685c9586 100644 --- a/docu/community-server.api.md +++ b/docu/community-server.api.md @@ -23,13 +23,13 @@ Additional session can be provided as GET-Parameter ```json { "state":"success", - "balance":1590.60, + "balance":15906078, "decay":15873851, "decay_date":"2021-04-16T11:47:21+00:00" } ``` -- `balance` : balance describes gradido +- `balance` : balance describes gradido cents which are 4 digits behind the separator. A balance value of 174500 equals therefor 17,45 GDD - `decay` : balance with decay on it at the time in decay_date, so it is the precise balance of user at time of calling this function - `decay_date`: date and time for decay amount, should be the time and date of function call @@ -59,16 +59,32 @@ Assuming: session is valid { "state":"success", "transactions": [ + { + "type": "decay", + "balance": "14.74", + "decay_duration": "4 days, 2 hours ago", + "memo": "" + }, { "name": "Max Mustermann", "email": "Maxim Mustermann", "type": "send", "transaction_id": 2, "date": "2021-02-19T13:25:36+00:00", - "balance": 192.0, + "balance": 192, "memo": "a piece of cake :)", "pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7" - } + }, + { + "name": "Gradido Akademie", + "type": "creation", + "transaction_id": 10, + "date": "2021-04-15T11:19:45+00:00", + "target_date": "2021-02-01T00:00:00+00:00", + "creation_amount": "1000", + "balance": "1000", + "memo": "AGE Februar 2021" + } ], "transactionExecutingCount": 0, "count": 1, @@ -95,8 +111,11 @@ Transaction: - `receiver`: user has received gradidos from another user - `transaction_id`: id of transaction in db, in stage2 also the hedera sequence number of transaction - `date`: date of ordering transaction (booking date) -- `balance`: Gradido +- `balance`: Gradido as float, max 2 Nachkommastellen, by creation balance after subtract decay amount - `memo`: Details about transaction +- `decay_duration`: only for decay, time duration for decay calculation in english text +- `creation_amount`: only for creation transaction, created account before decay +- `target_date`: only by creation transaction, target date for creation, start time for decay calculation (if < as global decay start time) ## Creation transaction Makes a creation transaction to create new Gradido @@ -150,7 +169,6 @@ with - `session_id`: optional, only used if cookie GRADIDO_LOGIN not exist and no sesion_id in php session - `email` or `username` or `pubkey`: used to identify how gets the gradidos (email and username are only aliases for pubkey) - `amount`: gdd amount to transfer in gradido cent (10000000 = 1000,00 GDD) -- `target_date`: target date for creation, can be max 3 months before current date, but not after current date, allowed formats do you find here: https://pocoproject.org/docs/Poco.DateTimeFormat.html - `memo`: text for receiver, currently saved as clear text in blockchain - `auto_sign`: if set to true, transaction will be directly signed on login-server and proceed if needed signs are there if set to false, transaction must be signed after on `http://localhost/account/checkTransactions` @@ -245,3 +263,41 @@ Without auto-sign the transaction is pending on the login-server and waits for t // TODO Is this in line with our usability goals? // TODO Should this not be handled client side? + +# Klicktipp + +## Subscribe +Subscribe current logged in user to gradido newsletter + +### Request +`GET http://localhost/api/klicktipp_subscribe/[session_id]` +Parts symbolized by [] are optional + - session_id: session will be searched in php session and GRADIDO_LOGIN cookie and if not found use this + +### Response +Assuming: session is valid + +```json +{ + "state": "success", + "redirect_url": "" +} +```` + +## Unsubscribe +Unsubscribe current logged in user from gradido newsletter + +### Request +`GET http://localhost/api/klicktipp_unsubscribe/[session_id]` +Parts symbolized by [] are optional + - session_id: session will be searched in php session and GRADIDO_LOGIN cookie and if not found use this + +### Response +Assuming: session is valid + +```json +{ + "state": "success" +} +```` +