diff --git a/community_server/Dockerfile b/community_server/Dockerfile index 2f3c0412a..cb4f67d27 100644 --- a/community_server/Dockerfile +++ b/community_server/Dockerfile @@ -9,5 +9,9 @@ WORKDIR /var/www/cakephp RUN mkdir logs && mkdir tmp && chmod 777 logs && chmod 777 tmp COPY ./community_server/ . COPY ./configs/community_server/app.php ./config/ -RUN composer update + +RUN composer update +RUN composer dump-autoload + + diff --git a/community_server/composer.json b/community_server/composer.json index 7eeb26887..784c6d123 100644 --- a/community_server/composer.json +++ b/community_server/composer.json @@ -30,7 +30,9 @@ "autoload": { "psr-4": { "App\\": "src/", - "" : "src/" + "" : "src/", + "GPBMetadata\\": "src/GPBMetadata", + "Model\\Messages\\Gradido\\" : "src/Model/Messages/Gradido" } }, "autoload-dev": { diff --git a/community_server/config/bootstrap.php b/community_server/config/bootstrap.php index c57f81374..55918ba20 100644 --- a/community_server/config/bootstrap.php +++ b/community_server/config/bootstrap.php @@ -193,6 +193,13 @@ Type::build('datetime') ->useImmutable(); Type::build('timestamp') ->useImmutable(); + +header('Access-Control-Allow-Origin: *'); +header('Access-Control-Allow-Methods: POST, GET, PUT, PATCH, DELETE, OPTIONS'); +header('Access-Control-Allow-Headers: *'); +if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { + exit(0); +} /* * Custom Inflector rules, can be set to correctly pluralize or singularize diff --git a/community_server/config/routes.php b/community_server/config/routes.php index 27d998f2c..ec3b5fd27 100644 --- a/community_server/config/routes.php +++ b/community_server/config/routes.php @@ -58,6 +58,7 @@ Router::scope('/', function (RouteBuilder $routes) { // Skip token check for API URLs. //die($request->getParam('controller')); $whitelist = ['JsonRequestHandler', 'ElopageWebhook']; + $ajaxWhitelist = ['TransactionSendCoins', 'TransactionCreations']; foreach($whitelist as $entry) { if($request->getParam('controller') === $entry) { @@ -68,15 +69,29 @@ Router::scope('/', function (RouteBuilder $routes) { return true; } $allowedCaller = Configure::read('API.allowedCaller'); + $ipPerHost = []; if($allowedCaller && count($allowedCaller) > 0) { $callerIp = $request->clientIp(); foreach($allowedCaller as $allowed) { $ip = gethostbyname($allowed); + $ipPerHost[$allowed] = $ip; if($ip === $callerIp) return true; } + //die("caller ip: $callerIp
"); } + //var_dump(['caller_ip' => $callerIp, 'ips' => $ipPerHost]); + die(json_encode(['state' => 'error', 'details' => ['caller_ip' => $callerIp, 'ips' => $ipPerHost]])); } } + // disable csfr for all ajax requests in ajax whitelisted controller + foreach($ajaxWhitelist as $entry) { + if($request->getParam('controller') === $entry) { + $action = $request->getParam('action'); + if(preg_match('/^ajax/', $action)) { + return true; + } + } + } }); // Register scoped middleware for in scopes. diff --git a/community_server/copy_to_www.sh b/community_server/copy_to_www.sh new file mode 100755 index 000000000..f6519919f --- /dev/null +++ b/community_server/copy_to_www.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +[! -z "${FOLDER_NAME}"] && FOLDER_NAME=community_server + +COLOR_GREEN="\033[0;32m" +COLOR_YELLOW="\e[33m" +COLOR_NONE="\033[0m" + +SCRIPT=`realpath -s $0` +SCRIPTPATH=`dirname $SCRIPT` +#echo -e "script: $SCRIPT, Path: $SCRIPTPATH " + +cd /var/www/html +if [ ! -d "$FOLDER_NAME" ] ; then + mkdir $FOLDER_NAME +else + chmod -R 0755 $FOLDER_NAME +fi +cd $FOLDER_NAME +cp -r $SCRIPTPATH/src . +cp -r $SCRIPTPATH/config . +cp -r $SCRIPTPATH/composer.json . +cp -r $SCRIPTPATH/webroot . +composer install +if [ ! -d "tmp" ] ; then + mkdir tmp + chown -R www-data:www-data ./tmp +fi +if [ ! -d "logs" ] ; then + mkdir logs + chown -R www-data:www-data ./logs +fi + +cd .. +chown -R www-data:www-data $FOLDER_NAME +chmod -R 0755 $FOLDER_NAME/src +chmod -R 0755 $FOLDER_NAME/config +chmod -R 0755 $FOLDER_NAME/webroot diff --git a/community_server/parse_proto.php b/community_server/parse_proto.sh similarity index 100% rename from community_server/parse_proto.php rename to community_server/parse_proto.sh diff --git a/community_server/skeema/gradido_community/state_balances.sql b/community_server/skeema/gradido_community/state_balances.sql index c8b013d44..5f79ce819 100644 --- a/community_server/skeema/gradido_community/state_balances.sql +++ b/community_server/skeema/gradido_community/state_balances.sql @@ -2,6 +2,7 @@ CREATE TABLE `state_balances` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `state_user_id` int(10) unsigned NOT NULL, `modified` datetime NOT NULL, + `record_date`datetime NULL, `amount` bigint(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/community_server/skeema/gradido_community/state_user_transactions.sql b/community_server/skeema/gradido_community/state_user_transactions.sql new file mode 100644 index 000000000..272552845 --- /dev/null +++ b/community_server/skeema/gradido_community/state_user_transactions.sql @@ -0,0 +1,9 @@ +CREATE TABLE `state_user_transactions` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `state_user_id` int UNSIGNED NOT NULL, + `transaction_id` int UNSIGNED NOT NULL, + `transaction_type_id` int UNSIGNED NOT NULL, + `balance` bigint(20) DEFAULT 0, + `balance_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + 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 2c59a17e0..fb0577034 100644 --- a/community_server/src/Controller/AppController.php +++ b/community_server/src/Controller/AppController.php @@ -139,7 +139,7 @@ class AppController extends Controller } } - protected function requestLogin($session_id = 0) + protected function requestLogin($session_id = 0, $redirect = true) { $session = $this->getRequest()->getSession(); // check login @@ -159,9 +159,9 @@ class AppController extends Controller if ($session_id != 0) { $userStored = $session->read('StateUser'); - $transactionPendings = $session->read('Transaction.pending'); - $transactionExecutings = $session->read('Transaction.executing'); + $transactionExecutings = $session->read('Transaction.executing'); + if ($session->read('session_id') != $session_id || ( $userStored && (!isset($userStored['id']) || !$userStored['email_checked'])) || intval($transactionPendings) > 0 || @@ -182,6 +182,8 @@ class AppController extends Controller $session->destroy(); } foreach ($json['user'] as $key => $value) { + // we don't need the id of user in login server db + if($key == 'id') continue; $session->write('StateUser.' . $key, $value); } //var_dump($json); @@ -238,12 +240,18 @@ class AppController extends Controller //echo $newStateUser->id; } } else { + if(!$redirect) { + return ['state' => 'error', 'msg' => 'no pubkey']; + } // we haven't get a pubkey? something seems to gone wrong on the login-server $this->Flash->error(__('no pubkey')); //var_dump($json); return $this->redirect($this->loginServerUrl . 'account/error500/noPubkey', 303); } } else { + if(!$redirect) { + return ['state' => 'not found', 'msg' => 'invalid session']; + } if ($json['state'] === 'not found') { $this->Flash->error(__('invalid session')); } else { @@ -255,6 +263,9 @@ class AppController extends Controller } } catch (\Exception $e) { $msg = $e->getMessage(); + if(!$redirect) { + return ['state' => 'error', 'msg' => 'login-server http request error', 'details' => $msg]; + } $this->Flash->error(__('error http request: ') . $msg); return $this->redirect(['controller' => 'Dashboard', 'action' => 'errorHttpRequest']); //continue; @@ -263,6 +274,9 @@ class AppController extends Controller } else { // no login //die("no login"); + if(!$redirect) { + return ['state' => 'error', 'msg' => 'not logged in']; + } if (isset($loginServer['path'])) { return $this->redirect($loginServer['path'], 303); } else { diff --git a/community_server/src/Controller/Component/JsonRequestClientComponent.php b/community_server/src/Controller/Component/JsonRequestClientComponent.php index 75d2c5a77..8a071b70b 100644 --- a/community_server/src/Controller/Component/JsonRequestClientComponent.php +++ b/community_server/src/Controller/Component/JsonRequestClientComponent.php @@ -15,7 +15,7 @@ use Cake\Core\Configure; class JsonRequestClientComponent extends Component { - public function sendTransaction($session_id, $base64Message, $user_balance = 0) { + public function sendTransaction($session_id, $base64Message, $user_balance = 0, $auto_sign = false) { if(!is_numeric($session_id)) { return ['state' => 'error', 'type' => 'parameter error', 'msg' => 'session_id isn\'t numeric']; } @@ -35,7 +35,8 @@ class JsonRequestClientComponent extends Component return $this->sendRequest(json_encode([ 'session_id' => $session_id, 'transaction_base64' => $base64Message, - 'balance' => $user_balance + 'balance' => $user_balance, + 'auto_sign' => $auto_sign ]), '/checkTransaction'); } diff --git a/community_server/src/Controller/StateBalancesController.php b/community_server/src/Controller/StateBalancesController.php index 5164dce4b..bddf35125 100644 --- a/community_server/src/Controller/StateBalancesController.php +++ b/community_server/src/Controller/StateBalancesController.php @@ -21,7 +21,7 @@ class StateBalancesController extends AppController { parent::initialize(); //$this->Auth->allow(['add', 'edit']); - $this->Auth->allow(['overview', 'overviewGdt', 'ajaxGetBalance']); + $this->Auth->allow(['overview', 'overviewGdt', 'ajaxGetBalance', 'ajaxListTransactions']); $this->loadComponent('JsonRequestClient'); } /** @@ -39,7 +39,33 @@ class StateBalancesController extends AppController $this->set(compact('stateBalances')); } - + private function updateBalances($state_user_id) + { + $state_balances = $this->StateBalances->find('all')->where(['state_user_id' => $state_user_id]); + if($state_balances->count() == 1) { + $stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions'); + $state_user_transactions = $stateUserTransactionsTable + ->find('all') + ->where(['state_user_id' => $state_user_id]) + ->order(['transaction_id ASC']) + ->contain(['']); + if($state_user_transactions->count() == 0){ + return; + } + $last_state_user_transaction = $state_user_transactions->last(); + $last_transaction = $this->StateBalance->newEntity(); + $last_transaction->amount = $last_state_user_transaction->balance; + $last_transaction->record_date = $last_state_user_transaction->balance_date; + // if entrys are nearly the same, we don't need doing anything + if(abs($last_transaction->decay - $state_balances->decay) < 100) { + return; + } + foreach($state_user_transactions as $state_user_transaction) { + + } + + } + } public function overview() { @@ -177,51 +203,73 @@ class StateBalancesController extends AppController $this->set('gdtSum', $gdtSum); } - public function ajaxGetBalance($session_id) + public function ajaxGetBalance($session_id = 0) { - if(!isset($session_id) || !$session_id) { - return $this->returnJson(['state' => 'error', 'msg' => 'invalid session']); + if(!$session_id) { + return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']); + } + $login_result = $this->requestLogin($session_id, false); + if($login_result !== true) { + return $this->returnJson($login_result); } - $startTime = microtime(true); $session = $this->getRequest()->getSession(); - $result = $this->requestLogin($session_id); - if ($result !== true) { - return $this->returnJson(['state' => 'error', 'msg' => 'session not found']); - } $user = $session->read('StateUser'); - //var_dump($user); - return $this->returnJson(['state' => 'success', 'balance' => $user['balance']]); + $public_key_bin = hex2bin($user['public_hex']); + $stateUserQuery = $this->StateBalances->StateUsers + ->find('all') + ->where(['public_key' => $public_key_bin]) + ->contain(['StateBalances']); + + $result_user_count = $stateUserQuery->count(); + if($result_user_count < 1) { + return $this->returnJson(['state' => 'success', 'balance' => 0]); + } + else if($result_user_count > 1) { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'multiple entrys found', + 'details' => ['public_key' => $user['public_hex'], 'entry_count' => $result_count] + ]); + } + $state_balances = $stateUserQuery->first()->state_balances; + $state_balances_count = count($state_balances); + if($state_balances_count > 1) { + return $this->returnJson(['state' => 'error', 'msg' => 'state balances count isn\'t as expected, expect 1 or 0', 'details' => $state_balances_count]); + } + if(!$state_balances_count) { + return $this->returnJson(['state' => 'success', 'balance' => 0]); + } + + return $this->returnJson(['state' => 'success', 'balance' => $state_balances[0]->amount]); } - public function ajaxListTransactions($session_id, $page, $count) + public function ajaxListTransactions($session_id = 0, $sort = 'ASC') { - if(!isset($session_id) || !$session_id) { - return $this->returnJson(['state' => 'error', 'msg' => 'invalid session']); + if(!$session_id) { + return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']); } + $startTime = microtime(true); - $session = $this->getRequest()->getSession(); - $result = $this->requestLogin($session_id); - if ($result !== true) { - return $this->returnJson(['state' => 'error', 'msg' => 'session not found']); + $login_result = $this->requestLogin($session_id, false); + if($login_result !== true) { + return $this->returnJson($login_result); } + $session = $this->getRequest()->getSession(); $user = $session->read('StateUser'); - - $gdtSum = 0; - + + $gdtSum = 0; $gdtEntries = $this->JsonRequestClient->sendRequestGDT(['email' => $user['email']], 'GdtEntries' . DS . 'sumPerEmailApi'); if('success' == $gdtEntries['state'] && 'success' == $gdtEntries['data']['state']) { $gdtSum = intval($gdtEntries['data']['sum']); } else { - if($user) { - + if($user) { $this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id']); } else { $this->addAdminError('StateBalancesController', 'overview', $gdtEntries, 0); } } - $creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations'); $creationTransactions = $creationsTable @@ -316,6 +364,9 @@ class StateBalancesController extends AppController ]); } uasort($transactions, array($this, 'sortTransactions')); + if($sort == 'DESC') { + $transactions = array_reverse($transactions); + } return $this->returnJson([ 'state' => 'success', 'transactions' => $transactions, diff --git a/community_server/src/Controller/StateUserTransactionsController.php b/community_server/src/Controller/StateUserTransactionsController.php new file mode 100644 index 000000000..8c252218c --- /dev/null +++ b/community_server/src/Controller/StateUserTransactionsController.php @@ -0,0 +1,290 @@ +Auth->allow(['add', 'edit']); + $this->Auth->allow(['ajaxListTransactions']); + //$this->loadComponent('JsonRequestClient'); + } + /** + * Index method + * + * @return \Cake\Http\Response|null + */ + public function index() + { + $this->paginate = [ + 'contain' => ['StateUsers', 'Transactions', 'TransactionTypes'], + ]; + $stateUserTransactions = $this->paginate($this->StateUserTransactions); + + $this->set(compact('stateUserTransactions')); + } + + public function sortTransactions($a, $b) + { + if ($a['date'] == $b['date']) { + return 0; + } + return ($a['date'] > $b['date']) ? -1 : 1; + } + + + public function ajaxListTransactions($page = 1, $count = 20) + { + $startTime = microtime(true); + $session = $this->getRequest()->getSession(); + $user = $session->read('StateUser'); + if(!$user) { + return $this->returnJson(['state' => 'error', 'msg' => 'user not found', 'details' => 'exist a valid session cookie?']); + } + + $paged_state_user_transactions = $this->StateUserTransactions + ->find('all') + ->where(['state_user_id' => $user['id'], 'transaction_type_id IN' => [1,2]]) + ->limit($count) + ->page($page) + ->order(['transaction_id']) + ; + $all_user_transactions_count = $this->StateUserTransactions + ->find('all') + ->where(['state_user_id' => $user['id'], 'transaction_type_id IN' => [1,2]]) + ->count() + ; + $creationTransaction_ids = []; + $transferTransaction_ids = []; + $allTransaction_ids = []; + foreach($paged_state_user_transactions as $state_user_transaction) { + $allTransaction_ids[] = $state_user_transaction->transaction_id; + switch($state_user_transaction->transaction_type_id) { + case 1: $creationTransaction_ids[] = $state_user_transaction->transaction_id; break; + case 2: $transferTransaction_ids[] = $state_user_transaction->transaction_id; break; + } + } + $transactionsTable = TableRegistry::getTableLocator()->get('Transactions'); + $transactionCreationsTable = TableRegistry::getTableLocator()->get('TransactionCreations'); + $transactionSendCoinsTable = TableRegistry::getTableLocator()->get('TransactionSendCoins'); + $stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers'); + if(count($allTransaction_ids) > 0) { + $transactionEntries = $transactionsTable->find('all')->where(['id IN' => $allTransaction_ids])->order(['id'])->toArray(); + } + if(count($creationTransaction_ids) > 0) { + $transactionCreations = $transactionCreationsTable->find('all')->where(['transaction_id IN' => $creationTransaction_ids]); + } + if(count($transferTransaction_ids)) { + $transactionTransfers = $transactionSendCoinsTable->find('all')->where(['transaction_id IN' => $transferTransaction_ids]); + } + //var_dump($transactions->all()); + + $transactions = []; + // creations + if(isset($transactionCreations)) { + foreach ($transactionCreations as $creation) { + //var_dump($creation); + $transaction_entries_index = array_search($creation->transaction_id, $allTransaction_ids); + if(FALSE === $transaction_entries_index) { + return $this->returnJson(['state' => 'error', 'msg' => 'code error', 'details' => 'creation, transaction_entries_index is FALSE, shouldn\'t occure']); + } + $transaction = $transactionEntries[$transaction_entries_index]; + array_push($transactions, [ + 'name' => 'Gradido Akademie', + 'type' => 'creation', + 'transaction_id' => $creation->transaction_id, + 'date' => $transaction->received, + 'balance' => $creation->amount, + 'memo' => $transaction->memo + ]); + } + } + + // involved users + if(isset($transactionTransfers)) { + $involvedUserIds = []; + + foreach ($transactionTransfers as $transfer) { + //var_dump($sendCoins); + if ($transfer->state_user_id != $user['id']) { + array_push($involvedUserIds, intval($transfer->state_user_id)); + } elseif ($transfer->receiver_user_id != $user['id']) { + array_push($involvedUserIds, intval($transfer->receiver_user_id)); + } + } + + // exchange key with values and drop duplicates + $involvedUser_temp = array_flip($involvedUserIds); + // exchange back + $involvedUserIds = array_flip($involvedUser_temp); + + $involvedUser = $stateUsersTable->find('all', [ + 'contain' => false, + 'where' => ['id IN' => $involvedUserIds], + 'fields' => ['id', 'first_name', 'last_name', 'email'] + ]); + //var_dump($involvedUser->toArray()); + $involvedUserIndices = []; + foreach ($involvedUser as $involvedUser) { + $involvedUserIndices[$involvedUser->id] = $involvedUser; + } + + // transfers - send coins + foreach($transactionTransfers as $transfer) + { + $transaction_entries_index = array_search($transfer->transaction_id, $allTransaction_ids); + if(FALSE === $transaction_entries_index) { + + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'code error', + 'details' => 'transfer, transaction_entries_index is FALSE, shouldn\'t occure', + 'data' => ['haystack' => $allTransaction_ids, 'needle' => $transfer->transaction_id] + ]); + } + $transaction = $transactionEntries[$transaction_entries_index]; + $type = ''; + $otherUser = null; + $other_user_public = ''; + + if ($transfer->state_user_id == $user['id']) { + $type = 'send'; + + if(isset($involvedUserIndices[$transfer->receiver_user_id])) { + $otherUser = $involvedUserIndices[$transfer->receiver_user_id]; + } + $other_user_public = bin2hex(stream_get_contents($transfer->receiver_public_key)); + } else if ($transfer->receiver_user_id == $user['id']) { + $type = 'receive'; + if(isset($involvedUserIndices[$transfer->state_user_id])) { + $otherUser = $involvedUserIndices[$transfer->state_user_id]; + } + if($transfer->sender_public_key) { + $other_user_public = bin2hex(stream_get_contents($transfer->sender_public_key)); + } + } + if(null == $otherUser) { + $otherUser = $stateUsersTable->newEntity(); + } + array_push($transactions, [ + 'name' => $otherUser->first_name . ' ' . $otherUser->last_name, + 'email' => $otherUser->email, + 'type' => $type, + 'transaction_id' => $transfer->transaction_id, + 'date' => $transaction->received, + 'balance' => $transfer->amount, + 'memo' => $transaction->memo, + 'pubkey' => $other_user_public + ]); + //*/ + + } + } + uasort($transactions, array($this, 'sortTransactions')); + + return $this->returnJson([ + 'state' => 'success', + 'transactions' => $transactions, + 'transactionExecutingCount' => $session->read('Transaction.executing'), + 'count' => $all_user_transactions_count, + 'timeUsed' => microtime(true) - $startTime + ]); + } + + /** + * View method + * + * @param string|null $id State User Transaction id. + * @return \Cake\Http\Response|null + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $stateUserTransaction = $this->StateUserTransactions->get($id, [ + 'contain' => ['StateUsers', 'Transactions', 'TransactionTypes'], + ]); + + $this->set('stateUserTransaction', $stateUserTransaction); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null Redirects on successful add, renders view otherwise. + */ + public function add() + { + $stateUserTransaction = $this->StateUserTransactions->newEntity(); + if ($this->request->is('post')) { + $stateUserTransaction = $this->StateUserTransactions->patchEntity($stateUserTransaction, $this->request->getData()); + if ($this->StateUserTransactions->save($stateUserTransaction)) { + $this->Flash->success(__('The state user transaction has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The state user transaction could not be saved. Please, try again.')); + } + $stateUsers = $this->StateUserTransactions->StateUsers->find('list', ['limit' => 200]); + $transactions = $this->StateUserTransactions->Transactions->find('list', ['limit' => 200]); + $transactionTypes = $this->StateUserTransactions->TransactionTypes->find('list', ['limit' => 200]); + $this->set(compact('stateUserTransaction', 'stateUsers', 'transactions', 'transactionTypes')); + } + + /** + * Edit method + * + * @param string|null $id State User Transaction 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) + { + $stateUserTransaction = $this->StateUserTransactions->get($id, [ + 'contain' => [], + ]); + if ($this->request->is(['patch', 'post', 'put'])) { + $stateUserTransaction = $this->StateUserTransactions->patchEntity($stateUserTransaction, $this->request->getData()); + if ($this->StateUserTransactions->save($stateUserTransaction)) { + $this->Flash->success(__('The state user transaction has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The state user transaction could not be saved. Please, try again.')); + } + $stateUsers = $this->StateUserTransactions->StateUsers->find('list', ['limit' => 200]); + $transactions = $this->StateUserTransactions->Transactions->find('list', ['limit' => 200]); + $transactionTypes = $this->StateUserTransactions->TransactionTypes->find('list', ['limit' => 200]); + $this->set(compact('stateUserTransaction', 'stateUsers', 'transactions', 'transactionTypes')); + } + + /** + * Delete method + * + * @param string|null $id State User Transaction 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']); + $stateUserTransaction = $this->StateUserTransactions->get($id); + if ($this->StateUserTransactions->delete($stateUserTransaction)) { + $this->Flash->success(__('The state user transaction has been deleted.')); + } else { + $this->Flash->error(__('The state user transaction could not be deleted. Please, try again.')); + } + + return $this->redirect(['action' => 'index']); + } +} diff --git a/community_server/src/Controller/TransactionCreationsController.php b/community_server/src/Controller/TransactionCreationsController.php index 9b05c1782..5e29a7997 100644 --- a/community_server/src/Controller/TransactionCreationsController.php +++ b/community_server/src/Controller/TransactionCreationsController.php @@ -35,6 +35,7 @@ class TransactionCreationsController extends AppController $this->loadComponent('JsonRequestClient'); //$this->Auth->allow(['add', 'edit']); //$this->Auth->allow('create'); + $this->Auth->allow('ajaxCreate'); $this->set( 'naviHierarchy', (new NaviHierarchy())-> @@ -446,6 +447,121 @@ class TransactionCreationsController extends AppController } } } + + public function ajaxCreate() + { + if ($this->request->is('post')) { + $startTime = microtime(true); + $jsonData = $this->request->input('json_decode', true); + $session_id = $jsonData['session_id']; + if(!isset($jsonData['session_id']) || intval($jsonData['session_id']) == 0) { + return $this->returnJson(['state' => 'parameter missing', 'msg' => 'invalid session id']); + } + + $login_result = $this->requestLogin($session_id, false); + if($login_result !== true) { + return $this->returnJson($login_result); + } + $session = $this->getRequest()->getSession(); + $user = $session->read('StateUser'); + + $memo = ''; + if(isset($jsonData['memo'])) { + $memo = $jsonData['memo']; + } + $auto_sign = true; + if(isset($jsonData['auto_sign'])) { + $auto_sign = $jsonData['auto_sign']; + } + if(!isset($jsonData['amount']) || intval($jsonData['amount']) <= 0) { + return $this->returnJson(['state' => 'parameter missing', 'msg' => 'amount not set or <= 0']); + } + if(!isset($jsonData['email'])) { + return $this->returnJson(['state' => 'parameter missing', 'msg' => 'no receiver email set']); + } + $amount = intval($jsonData['amount']); + if($amount > 10000000) { + return $this->returnJson(['state' => 'error', 'msg' => 'amount is to big']); + } + if($amount <= 0) { + return $this->returnJson(['state' => 'error', 'msg' => 'amount must be > 0']); + } + if(!isset($jsonData['target_date'])) { + return $this->returnJson(['state' => 'parameter missing', 'msg' => 'target_date not found']); + } + //$targetDate = $requestData['target_date']; + $stateUserTable = TableRegistry::getTableLocator()->get('StateUsers'); + $requestAnswear = $this->JsonRequestClient->sendRequest(json_encode([ + 'session_id' => $session_id, + 'email' => $jsonData['email'], + 'ask' => ['user.pubkeyhex', 'user.disabled', 'user.identHash'] + ]), '/getUserInfos'); + $receiverPubKeyHex = ''; + if('success' == $requestAnswear['state'] && 'success' == $requestAnswear['data']['state']) { + // will be allways 64 byte long, even if it is empty + $receiverPubKeyHex = $requestAnswear['data']['userData']['pubkeyhex']; + } else { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'receiver email not found on login-server', + 'details' => $requestAnswear, + 'timeUsed' => microtime(true) - $startTime + ]); + } + if($requestAnswear['data']['userData']['disabled']) { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'receiver is currently disabled, he cannot receive creations', + 'timeUsed' => microtime(true) - $startTime + ]); + } + + $builderResult = TransactionCreation::build( + $amount, + $memo, + $receiverPubKeyHex, + $requestAnswear['data']['userData']['identHash'], + new FrozenDate($jsonData['target_date']) + ); + $transaction_base64 = ''; + if ($builderResult['state'] == 'success') { + // todo: maybe use sodium base 64 encoder to make sure it can be readed from login-server + $transaction_base64 = base64_encode($builderResult['transactionBody']->serializeToString()); + } + + $requestResult = $this->JsonRequestClient->sendTransaction( + $session_id, + $transaction_base64, + $user['balance'], + $auto_sign + ); + if ($requestResult['state'] != 'success') { + $msg = 'error returned from login server'; + if ($requestResult['type'] === 'request error') { + $msg = 'login server couldn\'t reached'; + } + //$this->Flash->error(__('Error, please wait for the admin to fix it')); + return $this->returnJson([ + 'state' => 'request error', + 'msg' => $msg, + 'details' => $requestResult, + 'timeUsed' => microtime(true) - $startTime + ]); + } else { + $json = $requestResult['data']; + if ($json['state'] != 'success') { + if ($json['msg'] == 'session not found') { + $session->destroy(); + return $this->returnJson(['state' => 'error', 'msg' => 'session not found', 'timeUsed' => microtime(true) - $startTime]); + } else { + return $this->returnJson(['state' => 'error', 'msg' => 'login server error', 'details' => $json, 'timeUsed' => microtime(true) - $startTime]); + } + } else { + return $this->returnJson(['state' => 'success', 'timeUsed' => microtime(true) - $startTime]); + } + } + } + } /** * Add method diff --git a/community_server/src/Controller/TransactionSendCoinsController.php b/community_server/src/Controller/TransactionSendCoinsController.php index 40cccb90e..2f48de063 100644 --- a/community_server/src/Controller/TransactionSendCoinsController.php +++ b/community_server/src/Controller/TransactionSendCoinsController.php @@ -37,6 +37,7 @@ class TransactionSendCoinsController extends AppController //$this->Auth->allow(['add', 'edit']); $this->Auth->allow('create'); $this->Auth->allow('createRaw'); + $this->Auth->allow('ajaxCreate'); $this->set( 'naviHierarchy', (new NaviHierarchy())-> @@ -288,6 +289,143 @@ class TransactionSendCoinsController extends AppController $this->set('timeUsed', microtime(true) - $startTime); } + + public function ajaxCreate() + { + if ($this->request->is('post')) { + $startTime = microtime(true); + $jsonData = $this->request->input('json_decode', true); + $session_id = $jsonData['session_id']; + if(!$session_id) { + return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']); + } + + $login_result = $this->requestLogin($session_id, false); + if($login_result !== true) { + return $this->returnJson($login_result); + } + $session = $this->getRequest()->getSession(); + $user = $session->read('StateUser'); + + $receiverPubKeyHex = ''; + $senderPubKeyHex = $user['public_hex']; + + if(!isset($jsonData['amount']) || !isset($jsonData['email'])) { + return $this->returnJson(['state' => 'parameter missing', 'msg' => 'amount and/or email not set']); + } + $amount = intval($jsonData['amount']); + if($amount < 0) { + return $this->returnJson(['state' => 'error', 'msg' => 'amout must be > 0 and int']); + } + + if(!isset($user['balance']) || $jsonData['amount'] > $user['balance']) { + return $this->returnJson(['state' => 'error', 'msg' => 'not enough GDD']); + } + $memo = ''; + if(isset($jsonData['memo'])) { + $memo = $jsonData['memo']; + } + + $receiverEmail = $jsonData['email']; + if($receiverEmail === $user['email']) { + return $this->returnJson(['state' => 'error', 'msg' => 'sender and receiver email are the same']); + } + + $requestAnswear = $this->JsonRequestClient->sendRequest(json_encode([ + 'session_id' => $session_id, + 'email' => $receiverEmail, + 'ask' => ['user.pubkeyhex', 'user.disabled'] + ]), '/getUserInfos'); + if('success' == $requestAnswear['state'] && 'success' == $requestAnswear['data']['state']) { + // will be allways 64 byte long, even if it is empty + $receiverPubKeyHex = $requestAnswear['data']['userData']['pubkeyhex']; + } else { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'receiver email not found on login-server', + 'details' => $requestAnswear, + 'timeUsed' => microtime(true) - $startTime + ]); + } + if($requestAnswear['data']['userData']['disabled']) { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'receiver is currently disabled, he cannot receive payments', + 'timeUsed' => microtime(true) - $startTime + ]); + } + + + //var_dump($sessionStateUser); + + $builderResult = TransactionTransfer::build( + $amount, + $memo, + $receiverPubKeyHex, + $senderPubKeyHex + ); + $auto_sign = true; + if(isset($jsonData['auto_sign'])) { + $auto_sign = $jsonData['auto_sign']; + } + if($builderResult['state'] === 'success') { + + $http = new Client(); + try { + $loginServer = Configure::read('LoginServer'); + $url = $loginServer['host'] . ':' . $loginServer['port']; + + $response = $http->post($url . '/checkTransaction', json_encode([ + 'session_id' => $session_id, + 'transaction_base64' => base64_encode($builderResult['transactionBody']->serializeToString()), + 'auto_sign' => $auto_sign, + 'balance' => $user['balance'] + ]), ['type' => 'json']); + $json = $response->getJson(); + if($json['state'] != 'success') { + if($json['msg'] == 'session not found') { + $session->destroy(); + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'session not found', + 'details' => $session_id, + 'timeUsed' => microtime(true) - $startTime + ]); + //$this->Flash->error(__('session not found, please login again')); + } else { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'login server return error', + 'details' => $json, + 'timeUsed' => microtime(true) - $startTime + ]); + } + } else { + return $this->returnJson(['state' => 'success', 'timeUsed' => microtime(true) - $startTime]); + } + + } catch(\Exception $e) { + $msg = $e->getMessage(); + //$this->Flash->error(__('error http request: ') . $msg); + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'error http request', + 'details' => $msg, + 'timeUsed' => microtime(true) - $startTime + ]); + } + + } else { + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'no valid receiver public key given', + 'details' => $receiverPubKeyHex, + 'timeUsed' => microtime(true) - $startTime + ]); + } + } + return $this->returnJson(['state' => 'error', 'msg' => 'no post request']); + } public function createRaw() { diff --git a/community_server/src/Controller/TransactionsController.php b/community_server/src/Controller/TransactionsController.php index 2f0bc2747..4f8e04c2b 100644 --- a/community_server/src/Controller/TransactionsController.php +++ b/community_server/src/Controller/TransactionsController.php @@ -7,6 +7,7 @@ use Model\Transactions\Transaction; use Model\Transactions\TransactionBody; use Cake\Core\Configure; +use Cake\ORM\TableRegistry; /** * Transactions Controller @@ -40,6 +41,118 @@ class TransactionsController extends AppController $this->set(compact('transactions')); } + + public function synchronizeWithStateUserTransactions() + { + $startTime = microtime(true); + $missing_transaction_ids = []; + $transaction_ids = $this->Transactions + ->find('all') + ->select(['id', 'transaction_type_id']) + ->order(['id']) + ->all() + ; + $state_user_transaction_ids = $this->Transactions->StateUserTransactions + ->find('all') + ->select(['transaction_id']) + ->group(['transaction_id']) + ->order(['transaction_id']) + ->toArray() + ; + $i2 = 0; + $count1 = count($transaction_ids); + $count2 = count($state_user_transaction_ids); + foreach($transaction_ids as $i1 => $tr_id) { + //echo "$i1: "; + if($i2 >= $count2) { + $missing_transaction_ids[] = $tr_id; + //echo "adding to missing: $tr_id, continue
"; + continue; + } + $stu_id = $state_user_transaction_ids[$i2]; + if($tr_id->id == $stu_id->transaction_id) { + $i2++; + //echo "after i2++: $i2
"; + } else if($tr_id->id < $stu_id->transaction_id) { + $missing_transaction_ids[] = $tr_id; + //echo "adding to missing: $tr_id
"; + } + } + + if($this->request->is('POST')) { + $tablesForType = [ + 1 => $this->Transactions->TransactionCreations, + 2 => $this->Transactions->TransactionSendCoins, + 3 => $this->Transactions->TransactionGroupCreates, + 4 => $this->Transactions->TransactionGroupAddaddress, + 5 => $this->Transactions->TransactionGroupAddaddress + ]; + $idsForType = []; + foreach($missing_transaction_ids as $i => $transaction) { + if(!isset($idsForType[$transaction->transaction_type_id])) { + $idsForType[$transaction->transaction_type_id] = []; + } + $idsForType[$transaction->transaction_type_id][] = $transaction->id; + if($i > 200) break; + } + $entities = []; + $state_user_ids = []; + foreach($idsForType as $type_id => $transaction_ids) { + $specific_transactions = $tablesForType[$type_id]->find('all')->where(['transaction_id IN' => $transaction_ids])->toArray(); + $keys = $tablesForType[$type_id]->getSchema()->columns(); + //var_dump($keys); + foreach($specific_transactions as $specific) { + + foreach($keys as $key) { + if(preg_match('/_user_id/', $key)) { + $entity = $this->Transactions->StateUserTransactions->newEntity(); + $entity->transaction_id = $specific['transaction_id']; + $entity->transaction_type_id = $type_id; + $entity->state_user_id = $specific[$key]; + if(!in_array($entity->state_user_id, $state_user_ids)) { + array_push($state_user_ids, $entity->state_user_id); + } + $entities[] = $entity; + } + } + } + } + //var_dump($entities); + $stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers'); + $existingStateUsers = $stateUsersTable->find('all')->select(['id'])->where(['id IN' => $state_user_ids])->order(['id'])->all(); + $existing_state_user_ids = []; + $finalEntities = []; + foreach($existingStateUsers as $stateUser) { + $existing_state_user_ids[] = $stateUser->id; + } + foreach($entities as $entity) { + if(in_array($entity->state_user_id, $existing_state_user_ids)) { + array_push($finalEntities, $entity); + } + } + + + $results = $this->Transactions->StateUserTransactions->saveMany($finalEntities); + foreach($entities as $i => $entity) { + $errors = $entity->getErrors(); + /* if(count($errors)) { + echo "$i: "; + echo json_encode($errors); + echo "
"; + echo "state_user_id: " . $entity->state_user_id; + echo "
"; + }*/ + } + $this->set('results', $results); + $this->set('entities', $entities); + } + + $this->set('missing_transactions', $missing_transaction_ids); + $this->set('count1', $count1); + $this->set('count2', $count2); + $timeUsed = microtime(true) - $startTime; + $this->set('timeUsed', $timeUsed); + } /** * View method diff --git a/community_server/src/Model/Messages/GPBMetadata/BasicTypes.php b/community_server/src/GPBMetadata/BasicTypes.php similarity index 62% rename from community_server/src/Model/Messages/GPBMetadata/BasicTypes.php rename to community_server/src/GPBMetadata/BasicTypes.php index 113202053..f74eb472b 100644 --- a/community_server/src/Model/Messages/GPBMetadata/BasicTypes.php +++ b/community_server/src/GPBMetadata/BasicTypes.php @@ -15,14 +15,15 @@ class BasicTypes return; } $pool->internalAddGeneratedFile(hex2bin( - "0ae0030a10426173696354797065732e70726f746f12076772616469646f" . - "22380a034b657912110a076564323535313918022001280c480012170a0d" . - "656432353531395f726566313018032001280c480042050a036b65792258" . - "0a0d5369676e617475726550616972120e0a067075624b65791801200128" . - "0c12110a076564323535313918022001280c480012170a0d656432353531" . - "395f726566313018032001280c4800420b0a097369676e61747572652237" . - "0a0c5369676e61747572654d617012270a07736967506169721801200328" . - "0b32162e6772616469646f2e5369676e617475726550616972222b0a0954" . + "0afe030a10426173696354797065732e70726f746f12166d6f64656c2e6d" . + "657373616765732e6772616469646f22380a034b657912110a0765643235" . + "35313918022001280c480012170a0d656432353531395f72656631301803" . + "2001280c480042050a036b657922580a0d5369676e617475726550616972" . + "120e0a067075624b657918012001280c12110a0765643235353139180220" . + "01280c480012170a0d656432353531395f726566313018032001280c4800" . + "420b0a097369676e617475726522460a0c5369676e61747572654d617012" . + "360a077369675061697218012003280b32252e6d6f64656c2e6d65737361" . + "6765732e6772616469646f2e5369676e617475726550616972222b0a0954" . "696d657374616d70120f0a077365636f6e6473180120012803120d0a056e" . "616e6f7318022001280522230a1054696d657374616d705365636f6e6473" . "120f0a077365636f6e647318012001280322590a0c53656e646572416d6f" . diff --git a/community_server/src/GPBMetadata/StateCreateGroup.php b/community_server/src/GPBMetadata/StateCreateGroup.php new file mode 100644 index 000000000..7098eb808 --- /dev/null +++ b/community_server/src/GPBMetadata/StateCreateGroup.php @@ -0,0 +1,32 @@ +internalAddGeneratedFile(hex2bin( + "0ae4010a16537461746543726561746547726f75702e70726f746f12166d" . + "6f64656c2e6d657373616765732e6772616469646f22a9010a1053746174" . + "6543726561746547726f7570120c0a046e616d6518012001280912330a0e" . + "67726f75705075626c69634b657918022001280b321b2e6d6f64656c2e6d" . + "657373616765732e6772616469646f2e4b657912390a14706172656e7447" . + "726f75705075626c69634b657918032001280b321b2e6d6f64656c2e6d65" . + "7373616765732e6772616469646f2e4b65794a0408041005521168656465" . + "7261436f6e73656e7375734964620670726f746f33" + ), true); + + static::$is_initialized = true; + } +} + diff --git a/community_server/src/GPBMetadata/StateGroupChangeParent.php b/community_server/src/GPBMetadata/StateGroupChangeParent.php new file mode 100644 index 000000000..c87782041 --- /dev/null +++ b/community_server/src/GPBMetadata/StateGroupChangeParent.php @@ -0,0 +1,33 @@ +internalAddGeneratedFile(hex2bin( + "0a8a020a1c537461746547726f75704368616e6765506172656e742e7072" . + "6f746f12166d6f64656c2e6d657373616765732e6772616469646f22c901" . + "0a16537461746547726f75704368616e6765506172656e7412330a0e6772" . + "6f75705075626c69634b657918012001280b321b2e6d6f64656c2e6d6573" . + "73616765732e6772616469646f2e4b6579123c0a176e6577506172656e74" . + "47726f75705075626c69634b657918022001280b321b2e6d6f64656c2e6d" . + "657373616765732e6772616469646f2e4b6579123c0a176f6c6450617265" . + "6e7447726f75705075626c69634b657918032001280b321b2e6d6f64656c" . + "2e6d657373616765732e6772616469646f2e4b6579620670726f746f33" + ), true); + + static::$is_initialized = true; + } +} + diff --git a/community_server/src/GPBMetadata/Transaction.php b/community_server/src/GPBMetadata/Transaction.php new file mode 100644 index 000000000..d86999450 --- /dev/null +++ b/community_server/src/GPBMetadata/Transaction.php @@ -0,0 +1,32 @@ +internalAddGeneratedFile(hex2bin( + "0ae4010a115472616e73616374696f6e2e70726f746f12166d6f64656c2e" . + "6d657373616765732e6772616469646f22ae010a0b5472616e7361637469" . + "6f6e120a0a026964180120012804123a0a08726563656976656418022001" . + "280b32282e6d6f64656c2e6d657373616765732e6772616469646f2e5469" . + "6d657374616d705365636f6e647312340a067369674d617018032001280b" . + "32242e6d6f64656c2e6d657373616765732e6772616469646f2e5369676e" . + "61747572654d6170120e0a0674784861736818042001280c12110a09626f" . + "6479427974657318052001280c620670726f746f33" + ), true); + + static::$is_initialized = true; + } +} + diff --git a/community_server/src/GPBMetadata/TransactionBody.php b/community_server/src/GPBMetadata/TransactionBody.php new file mode 100644 index 000000000..61d99eb96 --- /dev/null +++ b/community_server/src/GPBMetadata/TransactionBody.php @@ -0,0 +1,46 @@ +internalAddGeneratedFile(hex2bin( + "0a84040a155472616e73616374696f6e426f64792e70726f746f12166d6f" . + "64656c2e6d657373616765732e6772616469646f1a165374617465437265" . + "61746547726f75702e70726f746f1a1c537461746547726f75704368616e" . + "6765506172656e742e70726f746f1a195472616e73616374696f6e437265" . + "6174696f6e2e70726f746f1a10426173696354797065732e70726f746f22" . + "e7020a0f5472616e73616374696f6e426f6479120c0a046d656d6f180120" . + "01280912390a076372656174656418022001280b32282e6d6f64656c2e6d" . + "657373616765732e6772616469646f2e54696d657374616d705365636f6e" . + "6473123f0a0b63726561746547726f757018062001280b32282e6d6f6465" . + "6c2e6d657373616765732e6772616469646f2e5374617465437265617465" . + "47726f75704800124b0a1167726f75704368616e6765506172656e741807" . + "2001280b322e2e6d6f64656c2e6d657373616765732e6772616469646f2e" . + "537461746547726f75704368616e6765506172656e74480012340a087472" . + "616e7366657218082001280b32202e6d6f64656c2e6d657373616765732e" . + "6772616469646f2e5472616e736665724800123f0a086372656174696f6e" . + "18092001280b322b2e6d6f64656c2e6d657373616765732e677261646964" . + "6f2e5472616e73616374696f6e4372656174696f6e480042060a04646174" . + "61620670726f746f33" + ), true); + + static::$is_initialized = true; + } +} + diff --git a/community_server/src/GPBMetadata/TransactionCreation.php b/community_server/src/GPBMetadata/TransactionCreation.php new file mode 100644 index 000000000..f1ce2cf1a --- /dev/null +++ b/community_server/src/GPBMetadata/TransactionCreation.php @@ -0,0 +1,32 @@ +internalAddGeneratedFile(hex2bin( + "0ae6010a195472616e73616374696f6e4372656174696f6e2e70726f746f" . + "12166d6f64656c2e6d657373616765732e6772616469646f22a8010a1354" . + "72616e73616374696f6e4372656174696f6e123e0a0e7265636569766572" . + "416d6f756e7418012001280b32262e6d6f64656c2e6d657373616765732e" . + "6772616469646f2e5265636569766572416d6f756e7412120a0a6964656e" . + "745f68617368180220012811123d0a0b7461726765745f64617465180320" . + "01280b32282e6d6f64656c2e6d657373616765732e6772616469646f2e54" . + "696d657374616d705365636f6e6473620670726f746f33" + ), true); + + static::$is_initialized = true; + } +} + diff --git a/community_server/src/Model/Messages/GPBMetadata/Transfer.php b/community_server/src/GPBMetadata/Transfer.php similarity index 51% rename from community_server/src/Model/Messages/GPBMetadata/Transfer.php rename to community_server/src/GPBMetadata/Transfer.php index f5236ee43..b0b2c3a2d 100644 --- a/community_server/src/Model/Messages/GPBMetadata/Transfer.php +++ b/community_server/src/GPBMetadata/Transfer.php @@ -16,11 +16,13 @@ class Transfer } \GPBMetadata\BasicTypes::initOnce(); $pool->internalAddGeneratedFile(hex2bin( - "0a8d010a0e5472616e736665722e70726f746f12076772616469646f226a" . - "0a085472616e73666572122c0a0d73656e646572416d6f756e7473180120" . - "03280b32152e6772616469646f2e53656e646572416d6f756e7412300a0f" . - "7265636569766572416d6f756e747318022003280b32172e677261646964" . - "6f2e5265636569766572416d6f756e74620670726f746f33" + "0abb010a0e5472616e736665722e70726f746f12166d6f64656c2e6d6573" . + "73616765732e6772616469646f2288010a085472616e73666572123b0a0d" . + "73656e646572416d6f756e747318012003280b32242e6d6f64656c2e6d65" . + "7373616765732e6772616469646f2e53656e646572416d6f756e74123f0a" . + "0f7265636569766572416d6f756e747318022003280b32262e6d6f64656c" . + "2e6d657373616765732e6772616469646f2e5265636569766572416d6f75" . + "6e74620670726f746f33" ), true); static::$is_initialized = true; diff --git a/community_server/src/Model/Entity/StateBalance.php b/community_server/src/Model/Entity/StateBalance.php index 30d0d091f..174e785b4 100644 --- a/community_server/src/Model/Entity/StateBalance.php +++ b/community_server/src/Model/Entity/StateBalance.php @@ -2,6 +2,7 @@ namespace App\Model\Entity; use Cake\ORM\Entity; +use Cake\I18n\Time; /** * StateBalance Entity @@ -28,6 +29,39 @@ class StateBalance extends Entity 'state_user_id' => true, 'modified' => true, 'amount' => true, + 'record_date' => true, 'state_user' => true ]; + + protected $_virtual = ['decay']; + + protected function _getDecay() + { + // decay factor in seconds per year + // q = e^((lg Kn - lg K0) / n) + // 0.999999978 + // + // 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->record_date->getTimestamp()); + if($decay_duration === 0) { + return $this->amount; + } + return $this->amount * pow(0.99999997802044727, $decay_duration); + + } + public function partDecay($target_date) + { + $decay_duration = intval($target_date->getTimestamp() - $this->record_date->getTimestamp()); + if($decay_duration <= 0) { + return $this->amount; + } + return $this->amount * pow(0.99999997802044727, $decay_duration); + } + + public function decayDuration($target_date) + { + return intval($target_date->getTimestamp() - $this->record_date->getTimestamp()); + } } diff --git a/community_server/src/Model/Entity/StateUserTransaction.php b/community_server/src/Model/Entity/StateUserTransaction.php new file mode 100644 index 000000000..9fed345a5 --- /dev/null +++ b/community_server/src/Model/Entity/StateUserTransaction.php @@ -0,0 +1,37 @@ + true, + 'transaction_id' => true, + 'transaction_type_id' => true, + 'state_user' => true, + 'transaction' => true, + 'transaction_type' => true, + ]; +} diff --git a/community_server/src/Model/Messages/GPBMetadata/StateCreateGroup.php b/community_server/src/Model/Messages/GPBMetadata/StateCreateGroup.php deleted file mode 100644 index 24ef6b2a7..000000000 --- a/community_server/src/Model/Messages/GPBMetadata/StateCreateGroup.php +++ /dev/null @@ -1,31 +0,0 @@ -internalAddGeneratedFile(hex2bin( - "0ab7010a16537461746543726561746547726f75702e70726f746f120767" . - "72616469646f228b010a10537461746543726561746547726f7570120c0a" . - "046e616d6518012001280912240a0e67726f75705075626c69634b657918" . - "022001280b320c2e6772616469646f2e4b6579122a0a14706172656e7447" . - "726f75705075626c69634b657918032001280b320c2e6772616469646f2e" . - "4b65794a04080410055211686564657261436f6e73656e73757349646206" . - "70726f746f33" - ), true); - - static::$is_initialized = true; - } -} - diff --git a/community_server/src/Model/Messages/GPBMetadata/StateGroupChangeParent.php b/community_server/src/Model/Messages/GPBMetadata/StateGroupChangeParent.php deleted file mode 100644 index 8f9111842..000000000 --- a/community_server/src/Model/Messages/GPBMetadata/StateGroupChangeParent.php +++ /dev/null @@ -1,31 +0,0 @@ -internalAddGeneratedFile(hex2bin( - "0ace010a1c537461746547726f75704368616e6765506172656e742e7072" . - "6f746f12076772616469646f229c010a16537461746547726f7570436861" . - "6e6765506172656e7412240a0e67726f75705075626c69634b6579180120" . - "01280b320c2e6772616469646f2e4b6579122d0a176e6577506172656e74" . - "47726f75705075626c69634b657918022001280b320c2e6772616469646f" . - "2e4b6579122d0a176f6c64506172656e7447726f75705075626c69634b65" . - "7918032001280b320c2e6772616469646f2e4b6579620670726f746f33" - ), true); - - static::$is_initialized = true; - } -} - diff --git a/community_server/src/Model/Messages/GPBMetadata/Transaction.php b/community_server/src/Model/Messages/GPBMetadata/Transaction.php deleted file mode 100644 index 9f1d8ff23..000000000 --- a/community_server/src/Model/Messages/GPBMetadata/Transaction.php +++ /dev/null @@ -1,31 +0,0 @@ -internalAddGeneratedFile(hex2bin( - "0ab7010a115472616e73616374696f6e2e70726f746f1207677261646964" . - "6f2290010a0b5472616e73616374696f6e120a0a02696418012001280412" . - "2b0a08726563656976656418022001280b32192e6772616469646f2e5469" . - "6d657374616d705365636f6e647312250a067369674d617018032001280b" . - "32152e6772616469646f2e5369676e61747572654d6170120e0a06747848" . - "61736818042001280c12110a09626f6479427974657318052001280c6206" . - "70726f746f33" - ), true); - - static::$is_initialized = true; - } -} - diff --git a/community_server/src/Model/Messages/GPBMetadata/TransactionBody.php b/community_server/src/Model/Messages/GPBMetadata/TransactionBody.php deleted file mode 100644 index d225389b6..000000000 --- a/community_server/src/Model/Messages/GPBMetadata/TransactionBody.php +++ /dev/null @@ -1,40 +0,0 @@ -internalAddGeneratedFile(hex2bin( - "0aec020a155472616e73616374696f6e426f64792e70726f746f12076772" . - "616469646f1a16537461746543726561746547726f75702e70726f746f1a" . - "1c537461746547726f75704368616e6765506172656e742e70726f746f1a" . - "195472616e73616374696f6e4372656174696f6e2e70726f746f22f0010a" . - "0f5472616e73616374696f6e426f6479120c0a046d656d6f180120012809" . - "12300a0b63726561746547726f757018022001280b32192e677261646964" . - "6f2e537461746543726561746547726f75704800123c0a1167726f757043" . - "68616e6765506172656e7418032001280b321f2e6772616469646f2e5374" . - "61746547726f75704368616e6765506172656e74480012250a087472616e" . - "7366657218042001280b32112e6772616469646f2e5472616e7366657248" . - "0012300a086372656174696f6e18052001280b321c2e6772616469646f2e" . - "5472616e73616374696f6e4372656174696f6e480042060a046461746162" . - "0670726f746f33" - ), true); - - static::$is_initialized = true; - } -} - diff --git a/community_server/src/Model/Messages/GPBMetadata/TransactionCreation.php b/community_server/src/Model/Messages/GPBMetadata/TransactionCreation.php deleted file mode 100644 index c8984298c..000000000 --- a/community_server/src/Model/Messages/GPBMetadata/TransactionCreation.php +++ /dev/null @@ -1,29 +0,0 @@ -internalAddGeneratedFile(hex2bin( - "0a88010a195472616e73616374696f6e4372656174696f6e2e70726f746f" . - "12076772616469646f225a0a135472616e73616374696f6e437265617469" . - "6f6e122f0a0e7265636569766572416d6f756e7418012001280b32172e67" . - "72616469646f2e5265636569766572416d6f756e7412120a0a6964656e74" . - "5f68617368180220012811620670726f746f33" - ), true); - - static::$is_initialized = true; - } -} - diff --git a/community_server/src/Model/Table/StateUserTransactionsTable.php b/community_server/src/Model/Table/StateUserTransactionsTable.php new file mode 100644 index 000000000..6cfe94a23 --- /dev/null +++ b/community_server/src/Model/Table/StateUserTransactionsTable.php @@ -0,0 +1,85 @@ +setTable('state_user_transactions'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('StateUsers', [ + 'foreignKey' => 'state_user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Transactions', [ + 'foreignKey' => 'transaction_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 + ->nonNegativeInteger('id') + ->allowEmptyString('id', null, 'create'); + + 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_id'], 'Transactions')); + $rules->add($rules->existsIn(['transaction_type_id'], 'TransactionTypes')); + + return $rules; + } +} diff --git a/community_server/src/Model/Table/TransactionsTable.php b/community_server/src/Model/Table/TransactionsTable.php index 75659a5b2..6777070fe 100644 --- a/community_server/src/Model/Table/TransactionsTable.php +++ b/community_server/src/Model/Table/TransactionsTable.php @@ -73,6 +73,9 @@ class TransactionsTable extends Table $this->hasMany('TransactionSignatures', [ 'foreignKey' => 'transaction_id' ]); + $this->hasMany('StateUserTransactions', [ + 'foreignKey' => 'transaction_id' + ]); } /** diff --git a/community_server/src/Model/Transactions/TransactionBase.php b/community_server/src/Model/Transactions/TransactionBase.php index 4198fbaaa..80ce8ef5d 100644 --- a/community_server/src/Model/Transactions/TransactionBase.php +++ b/community_server/src/Model/Transactions/TransactionBase.php @@ -6,7 +6,7 @@ use Cake\ORM\TableRegistry; class TransactionBase { private $errors = []; - static $stateUsersTable = null; + static $tables = []; public function getErrors() { return $this->errors; @@ -24,18 +24,17 @@ class TransactionBase { return count($this->errors) > 0; } - public static function getStateUsersTable() - { - if(!self::$stateUsersTable) { - self::$stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); + public static function getTable($tableName) { + if(!isset(self::$tables[$tableName])) { + self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName); } - return self::$stateUsersTable; + return self::$tables[$tableName]; } protected function getStateUserId($publicKey) { - $stateUsersTable = self::getStateUsersTable(); + $stateUsersTable = self::getTable('state_users'); $stateUser = $stateUsersTable->find('all')->select(['id'])->where(['public_key' => $publicKey])->first(); if($stateUser) { return $stateUser->id; @@ -53,7 +52,7 @@ class TransactionBase { } protected function getStateUser($id) { - $stateUsersTable = self::getStateUsersTable(); + $stateUsersTable = self::getTable('state_users'); $stateUser = $stateUsersTable->get($id); if($stateUser) { return $stateUser; @@ -63,9 +62,9 @@ class TransactionBase { } - protected function updateStateBalance($stateUserId, $addAmountCent) { + protected function updateStateBalance($stateUserId, $addAmountCent, $recordDate) { $finalBalance = 0; - $stateBalancesTable = TableRegistry::getTableLocator()->get('stateBalances'); + $stateBalancesTable = self::getTable('stateBalances'); $stateBalanceQuery = $stateBalancesTable ->find('all') ->select(['amount', 'id']) @@ -75,12 +74,14 @@ class TransactionBase { if($stateBalanceQuery->count() > 0) { $stateBalanceEntry = $stateBalanceQuery->first(); + $stateBalanceEntry->amount = $stateBalanceEntry->partDecay($recordDate) + $addAmountCent; $stateBalanceEntry->amount += $addAmountCent; } else { $stateBalanceEntry = $stateBalancesTable->newEntity(); $stateBalanceEntry->state_user_id = $stateUserId; $stateBalanceEntry->amount = $addAmountCent; } + $stateBalanceEntry->record_date = $recordDate; $finalBalance = $stateBalanceEntry->amount; //echo "\ntry to save: "; var_dump($stateBalanceEntry); echo "\n"; if(!$stateBalancesTable->save($stateBalanceEntry)) { @@ -90,4 +91,32 @@ class TransactionBase { } return $finalBalance; } + + protected function addStateUserTransaction($stateUserId, $transactionId, $transactionTypeId, $balance) { + $stateUserTransactionTable = self::getTable('state_user_transactions'); + $stateUserTransactions = $stateUserTransactionTable + ->find('all') + ->where(['state_user_id' => $stateUserId]) + ->order(['transaction_id DESC']); + + if($stateUserTransactions->count() > 0) { + $stateBalanceTable = self::getTable('state_balances'); + $balance_entity = $stateBalanceTable->newEntity(); + $balance_entity->amount = $stateUserTransactions->first()->balance; + $balance_entity->record_date = $stateUserTransactions->first()->balance_date; + $balance = $balance_entity->decay + $balance; + } + $entity = $stateUserTransactionTable->newEntity(); + $entity->state_user_id = $stateUserId; + $entity->transaction_id = $transactionId; + $entity->transaction_type_id = $transactionTypeId; + $entity->balance = $balance; + + if(!$stateUserTransactionTable->save($entity)) { + $errors = $entity->getErrors(); + $this->addError('TransactionBase::addStateUserTransaction', 'error saving state user balance with: ' . json_encode($errors)); + return false; + } + return true; + } } \ No newline at end of file diff --git a/community_server/src/Model/Transactions/TransactionBody.php b/community_server/src/Model/Transactions/TransactionBody.php index 0dca15637..8164f33f7 100644 --- a/community_server/src/Model/Transactions/TransactionBody.php +++ b/community_server/src/Model/Transactions/TransactionBody.php @@ -79,7 +79,7 @@ class TransactionBody extends TransactionBase { if ($transactionsTable->save($transactionEntity)) { // success $this->mTransactionID = $transactionEntity->id; - if(!$this->mSpecificTransaction->save($transactionEntity->id, $firstPublic)) { + if(!$this->mSpecificTransaction->save($transactionEntity->id, $firstPublic, $transactionEntity->received)) { $this->addErrors($this->mSpecificTransaction->getErrors()); return false; } diff --git a/community_server/src/Model/Transactions/TransactionCreation.php b/community_server/src/Model/Transactions/TransactionCreation.php index d9caa9f7b..e8c6133cb 100644 --- a/community_server/src/Model/Transactions/TransactionCreation.php +++ b/community_server/src/Model/Transactions/TransactionCreation.php @@ -189,6 +189,12 @@ class TransactionCreation extends TransactionBase { return false; } } else {*/ + if($newSum2 <= 0) { + $this->addError( + 'TransactionCreation::validate', + 'Creation less than 0 GDD per Month for '. $receiverEmail .' in target_date not allowed' + ); + } if($newSum2 > 10000000) { $this->addError( 'TransactionCreation::validate', @@ -225,16 +231,27 @@ class TransactionCreation extends TransactionBase { } // update state balance - if(false === $this->updateStateBalance($receiverUserId, $this->getAmount())) { + $final_balance = $this->updateStateBalance($receiverUserId, $this->getAmount(), $transactionCreationEntity->target_date); + if(false === $final_balance) { return false; } - + $target_date = new FrozenDate($transactionCreationEntity->target_date); + $stateBalancesTable = self::getTable('stateBalances'); + $state_balance = $stateBalancesTable->newEntity(); + $state_balance->amount = $this->getAmount(); + $state_balance->record_date = $target_date; + // decay is a virtual field which is calculated from amount and now() - record_date + if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 1, $state_balance->decay)) { + return false; + } return true; } public function sendNotificationEmail($memo) { + $disable_email = Configure::read('disableEmail', false); + if($disable_email) return true; // send notification email $receiverUserId = $this->getStateUserId($this->getReceiverPublic()); $receiverUser = $this->getStateUser($receiverUserId); diff --git a/community_server/src/Model/Transactions/TransactionTransfer.php b/community_server/src/Model/Transactions/TransactionTransfer.php index c89a0f175..a509cf0f3 100644 --- a/community_server/src/Model/Transactions/TransactionTransfer.php +++ b/community_server/src/Model/Transactions/TransactionTransfer.php @@ -154,11 +154,15 @@ class TransactionTransfer extends TransactionBase { $this->addError($functionName, 'sender amount doesn\'t match receiver amount'); return false; } + if($senderSum < 0) { + $this->addError($functionName, 'negative amount not supported'); + return false; + } //die("\n"); return true; } - public function save($transaction_id, $firstPublic) { + public function save($transaction_id, $firstPublic, $received) { static $functionName = 'TransactionCreation::save'; @@ -182,11 +186,11 @@ class TransactionTransfer extends TransactionBase { return false; } - $finalSenderBalance = $this->updateStateBalance($senderUserId, -$senderAmount->getAmount()); + $finalSenderBalance = $this->updateStateBalance($senderUserId, -$senderAmount->getAmount(), $received); if(false === $finalSenderBalance) { return false; } - if(false === $this->updateStateBalance($receiverUserId, $receiverAmount->getAmount())) { + if(false === $this->updateStateBalance($receiverUserId, $receiverAmount->getAmount(), $received)) { return false; } @@ -203,8 +207,12 @@ class TransactionTransfer extends TransactionBase { return false; } - - + if(!$this->addStateUserTransaction($senderUserId, $transaction_id, 2, $senderAmount->getAmount())) { + return false; + } + if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 2, -$senderAmount->getAmount())) { + return false; + } //$this->addError('TransactionTransfer::save', 'not implemented yet'); //return false; @@ -214,7 +222,9 @@ class TransactionTransfer extends TransactionBase { public function sendNotificationEmail($memo) { // send notification email - + $disable_email = Configure::read('disableEmail', false); + if($disable_email) return true; + $senderAmount = $this->protoTransactionTransfer->getSenderAmounts()[0]; $receiverAmount = $this->protoTransactionTransfer->getReceiverAmounts()[0]; $senderUserId = $this->getStateUserId($senderAmount->getEd25519SenderPubkey()); diff --git a/community_server/src/Template/StateUserTransactions/add.ctp b/community_server/src/Template/StateUserTransactions/add.ctp new file mode 100644 index 000000000..b131a43e5 --- /dev/null +++ b/community_server/src/Template/StateUserTransactions/add.ctp @@ -0,0 +1,31 @@ + + +
+ Form->create($stateUserTransaction) ?> +
+ + Form->control('state_user_id', ['options' => $stateUsers]); + echo $this->Form->control('transaction_id', ['options' => $transactions]); + echo $this->Form->control('transaction_type_id', ['options' => $transactionTypes]); + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
diff --git a/community_server/src/Template/StateUserTransactions/edit.ctp b/community_server/src/Template/StateUserTransactions/edit.ctp new file mode 100644 index 000000000..eec26e522 --- /dev/null +++ b/community_server/src/Template/StateUserTransactions/edit.ctp @@ -0,0 +1,37 @@ + + +
+ Form->create($stateUserTransaction) ?> +
+ + Form->control('state_user_id', ['options' => $stateUsers]); + echo $this->Form->control('transaction_id', ['options' => $transactions]); + echo $this->Form->control('transaction_type_id', ['options' => $transactionTypes]); + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
diff --git a/community_server/src/Template/StateUserTransactions/index.ctp b/community_server/src/Template/StateUserTransactions/index.ctp new file mode 100644 index 000000000..9bdd3d6b3 --- /dev/null +++ b/community_server/src/Template/StateUserTransactions/index.ctp @@ -0,0 +1,57 @@ + + +
+

+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('state_user_id') ?>Paginator->sort('transaction_id') ?>Paginator->sort('transaction_type_id') ?>
Number->format($stateUserTransaction->id) ?>has('state_user') ? $this->Html->link($stateUserTransaction->state_user->email, ['controller' => 'StateUsers', 'action' => 'view', $stateUserTransaction->state_user->id]) : '' ?>has('transaction') ? $this->Html->link($stateUserTransaction->transaction->id, ['controller' => 'Transactions', 'action' => 'view', $stateUserTransaction->transaction->id]) : '' ?>has('transaction_type') ? $this->Html->link($stateUserTransaction->transaction_type->name, ['controller' => 'TransactionTypes', 'action' => 'view', $stateUserTransaction->transaction_type->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $stateUserTransaction->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $stateUserTransaction->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $stateUserTransaction->id], ['confirm' => __('Are you sure you want to delete # {0}?', $stateUserTransaction->id)]) ?> +
+
+ +

Paginator->counter(['format' => __('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')]) ?>

+
+
diff --git a/community_server/src/Template/StateUserTransactions/view.ctp b/community_server/src/Template/StateUserTransactions/view.ctp new file mode 100644 index 000000000..13c05347b --- /dev/null +++ b/community_server/src/Template/StateUserTransactions/view.ctp @@ -0,0 +1,42 @@ + + +
+

id) ?>

+ + + + + + + + + + + + + + + + + +
has('state_user') ? $this->Html->link($stateUserTransaction->state_user->email, ['controller' => 'StateUsers', 'action' => 'view', $stateUserTransaction->state_user->id]) : '' ?>
has('transaction') ? $this->Html->link($stateUserTransaction->transaction->id, ['controller' => 'Transactions', 'action' => 'view', $stateUserTransaction->transaction->id]) : '' ?>
has('transaction_type') ? $this->Html->link($stateUserTransaction->transaction_type->name, ['controller' => 'TransactionTypes', 'action' => 'view', $stateUserTransaction->transaction_type->id]) : '' ?>
Number->format($stateUserTransaction->id) ?>
+
diff --git a/community_server/src/Template/Transactions/synchronize_with_state_user_transactions.ctp b/community_server/src/Template/Transactions/synchronize_with_state_user_transactions.ctp new file mode 100644 index 000000000..a4b48cb14 --- /dev/null +++ b/community_server/src/Template/Transactions/synchronize_with_state_user_transactions.ctp @@ -0,0 +1,46 @@ + +
+

Synchronize state_user_transactions with transactions

+

transactions count:

+

state_user_transaction count:

+

Missing count:

+

First 10 Missing ids:

+

$id) { + if($i > 10) break; + if($i > 0) echo ', '; + echo $id['id']; +} ?>

+ + +

Synchronize errors:

+ + + + Form->create() ?> + Form->button(__('Synchronize')) ?> + Form->end() ?> +
diff --git a/community_server/tests/Fixture/TransactionCreationsFixture.php b/community_server/tests/Fixture/TransactionCreationsFixture.php index d34a235a5..593c9efe4 100644 --- a/community_server/tests/Fixture/TransactionCreationsFixture.php +++ b/community_server/tests/Fixture/TransactionCreationsFixture.php @@ -45,21 +45,21 @@ class TransactionCreationsFixture extends TestFixture [ 'id' => 1, 'transaction_id' => 1, - 'state_user_id' => 2, + 'state_user_id' => 1, 'amount' => 10000000, 'ident_hash' => hex2bin('3235303332373635330000000000000000000000000000000000000000000000') ], [ 'id' => 2, 'transaction_id' => 2, - 'state_user_id' => 2, + 'state_user_id' => 1, 'amount' => 10000000, 'ident_hash' => hex2bin('3235303332373635330000000000000000000000000000000000000000000000') ], [ 'id' => 3, 'transaction_id' => 3, - 'state_user_id' => 2, + 'state_user_id' => 1, 'amount' => 10000000, 'ident_hash' => hex2bin('3235303332373635330000000000000000000000000000000000000000000000') ], diff --git a/community_server/tests/Fixture/TransactionSendCoinsFixture.php b/community_server/tests/Fixture/TransactionSendCoinsFixture.php index 9f7bc4a67..d3686a3b2 100644 --- a/community_server/tests/Fixture/TransactionSendCoinsFixture.php +++ b/community_server/tests/Fixture/TransactionSendCoinsFixture.php @@ -43,10 +43,10 @@ class TransactionSendCoinsFixture extends TestFixture [ 'id' => 1, 'transaction_id' => 4, - 'state_user_id' => 2, - 'receiver_public_key' => '0x80183e03535d17a54ff1fd7dbaed86939d423a19a258c26b8e338ce601338355', - 'receiver_user_id' => 1, - 'amount' => 150000001, + 'state_user_id' => 1, + 'receiver_public_key' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d', + 'receiver_user_id' => 4, + 'amount' => 15000000, 'sender_final_balance' => 15000000 ], ]; diff --git a/community_server/tests/TestCase/Controller/StateBalancesControllerTest.php b/community_server/tests/TestCase/Controller/StateBalancesControllerTest.php index cfa59d80b..2901015cf 100644 --- a/community_server/tests/TestCase/Controller/StateBalancesControllerTest.php +++ b/community_server/tests/TestCase/Controller/StateBalancesControllerTest.php @@ -67,19 +67,52 @@ class StateBalancesControllerTest extends TestCase public function testAjaxGetBalance() { $session_id = rand(); - $balance = rand(); $this->session([ 'session_id' => $session_id, 'Transaction' => ['pending' => 0, 'executing' => 0], 'StateUser' => [ - 'id' => 2, // 1 don't work, I don't know why + 'id' => 1, 'email_checked' => 1, - 'balance' => $balance + 'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d' ] ]); //echo "balance: $balance"; $this->getAndParse('/state-balances/ajaxGetBalance/' . $session_id, - ['state' => 'success', 'balance' => $balance] + ['state' => 'success', 'balance' => 1200000] + ); + } + + public function testAjaxGetBalanceInvalidSession() + { + $session_id = rand(); + $this->session([ + 'session_id' => $session_id, + 'Transaction' => ['pending' => 0, 'executing' => 0], + 'StateUser' => [ + 'email_checked' => 1, + 'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d' + ] + ]); + //echo "balance: $balance"; + $this->getAndParse('/state-balances/ajaxGetBalance/' . 1211, + ['state' => 'not found', 'msg' => 'invalid session'] + ); + } + + public function testAjaxGetBalanceInvalidSessionId() + { + $session_id = rand(); + $this->session([ + 'session_id' => $session_id, + 'Transaction' => ['pending' => 0, 'executing' => 0], + 'StateUser' => [ + 'email_checked' => 1, + 'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d' + ] + ]); + //echo "balance: $balance"; + $this->getAndParse('/state-balances/ajaxGetBalance' , + ['state' => 'error', 'msg' => 'invalid session id'] ); } @@ -90,7 +123,38 @@ class StateBalancesControllerTest extends TestCase */ public function testAjaxListTransactions() { - $this->markTestIncomplete('Not implemented yet.'); + //ajaxListTransactions + $session_id = rand(); + $this->session([ + 'session_id' => $session_id, + 'Transaction' => ['pending' => 0, 'executing' => 0], + 'StateUser' => [ + 'id' => 1, + 'first_name' => 'Dario', + 'last_name' => 'Frodo', + 'email_checked' => 1, + 'email' => 'fördertest@gradido.org', + 'public_hex' => '94ae135b93cd9f33752b4e55c41903a3faa13a75bb90bfd411ea1d4a1a5e711f' + ] + ]); + //echo "balance: $balance"; + $this->getAndParse('/state-balances/ajaxListTransactions/' . $session_id, + [ + 'state' => 'success', 'transactions' => [[ + 'name' => 'Dario Frodo', + 'email'=> 'dariofrodo@gmx.de', + 'type'=> '', + 'transaction_id' => 4, + 'date' => '2021-02-19T13:27:14+00:00', + 'balance' => 150000001, + 'memo' => '' + ]], + 'transactionExecutingCount' => 0, + 'count' => 1, + 'gdtSum' => 0, + 'timeUsed' => 0.03168010711669922 + ] + ); } /** @@ -169,10 +233,16 @@ class StateBalancesControllerTest extends TestCase $responseBodyString = (string)$this->_response->getBody(); $json = json_decode($responseBodyString); $this->assertNotFalse($json); - + if(is_array($expected)) { + // copy timeUsed because this value will be variy always + if(isset($expected['timeUsed']) && isset($json->timeUsed)) { + $expected['timeUsed'] = $json->timeUsed; + } $expected = json_encode($expected); } + + $this->assertEquals($expected, $responseBodyString); } }