Merge branch 'master' into login_build_alpine

This commit is contained in:
einhornimmond 2021-05-13 11:21:06 +02:00 committed by Ulf Gebhardt
commit 06c420dc2c
No known key found for this signature in database
GPG Key ID: 81308EFE29ABFEBD
44 changed files with 1062 additions and 990 deletions

View File

@ -4,8 +4,129 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [1.0.1](https://github.com/gradido/gradido/compare/0.9.4...1.0.1)
- Send button only click [`#427`](https://github.com/gradido/gradido/pull/427)
- use new function for balance overview in old frontend, update balance… [`#422`](https://github.com/gradido/gradido/pull/422)
- thx.vue coloured background removed. design adapted to app [`#426`](https://github.com/gradido/gradido/pull/426)
- translation password rules in Register.vue and ResetPasswort.vue fixed [`#424`](https://github.com/gradido/gradido/pull/424)
- 06x style [`#419`](https://github.com/gradido/gradido/pull/419)
- feat: Dash is Shown When Balance is Loading [`#396`](https://github.com/gradido/gradido/pull/396)
- refactor: Split GddSend into Components [`#415`](https://github.com/gradido/gradido/pull/415)
- fix: Set Maximum Transactions Loaded to 1000 [`#395`](https://github.com/gradido/gradido/pull/395)
- BUG : preRELEASE : thx transaction false [`#394`](https://github.com/gradido/gradido/pull/394)
- feat: Validation of Input Fields of GddSend [`#386`](https://github.com/gradido/gradido/pull/386)
- add validation, check if user has tried to send themself gradidos [`#277`](https://github.com/gradido/gradido/pull/277)
- fix link generation [`#347`](https://github.com/gradido/gradido/pull/347)
- Community start decay [`#387`](https://github.com/gradido/gradido/pull/387)
- transaction error message, translations [`#388`](https://github.com/gradido/gradido/pull/388)
- docu: locales schöpfen-mysql befehl [`#392`](https://github.com/gradido/gradido/pull/392)
- Fix: QR Scanner Hide [`#380`](https://github.com/gradido/gradido/pull/380)
- change design- dark-blue of text-ligth [`#381`](https://github.com/gradido/gradido/pull/381)
- spelling & translation [`#385`](https://github.com/gradido/gradido/pull/385)
- 350 6 login [`#383`](https://github.com/gradido/gradido/pull/383)
- fix: breakout error [`#375`](https://github.com/gradido/gradido/pull/375)
- 233-Support-Button fix, and col error fix [`#343`](https://github.com/gradido/gradido/pull/343)
- fix: membersarea open in a new tap [`#370`](https://github.com/gradido/gradido/pull/370)
- 00x table footer componente [`#345`](https://github.com/gradido/gradido/pull/345)
- clickevent from icon to button [`#364`](https://github.com/gradido/gradido/pull/364)
- 404 link to login page fix [`#366`](https://github.com/gradido/gradido/pull/366)
- bug: session_id vs sessionId [`#365`](https://github.com/gradido/gradido/pull/365)
- eslint rule standard [`#344`](https://github.com/gradido/gradido/pull/344)
- don't show decays smaller than 0,01 GDD [`#329`](https://github.com/gradido/gradido/pull/329)
- 338 - mt-5 margin top 5 eingebunden [`#341`](https://github.com/gradido/gradido/pull/341)
- feat: Update Transactions When GddTable Is Rendered [`#339`](https://github.com/gradido/gradido/pull/339)
- my profile auskommentiert [`#337`](https://github.com/gradido/gradido/pull/337)
- give balance as float value in GDD (not longer GDD cent) [`#273`](https://github.com/gradido/gradido/pull/273)
- fix error with password reset email [`#276`](https://github.com/gradido/gradido/pull/276)
- transaction.show_all in en.json hinzugefügt [`#335`](https://github.com/gradido/gradido/pull/335)
- refactor: Add Paramerts to ListTransactions API Call [`#332`](https://github.com/gradido/gradido/pull/332)
- css abstände vom rand in mobilen style [`#272`](https://github.com/gradido/gradido/pull/272)
- error messages are displayed [`#304`](https://github.com/gradido/gradido/pull/304)
- cancel to reset, form rest event added [`#334`](https://github.com/gradido/gradido/pull/334)
- remove from error messages because its no longer exist [`#330`](https://github.com/gradido/gradido/pull/330)
- xx deleted [`#333`](https://github.com/gradido/gradido/pull/333)
- fix bug on Login group add host [`#274`](https://github.com/gradido/gradido/pull/274)
- transactionslist load and icon [`#324`](https://github.com/gradido/gradido/pull/324)
- THX changed to Thank you [`#305`](https://github.com/gradido/gradido/pull/305)
- fix_bug_template [`#284`](https://github.com/gradido/gradido/pull/284)
- feat: Restructure Overview [`#271`](https://github.com/gradido/gradido/pull/271)
- fix: Dynamic Balance in User Profile [`#278`](https://github.com/gradido/gradido/pull/278)
- refactor: Test and Clean Up Store [`#270`](https://github.com/gradido/gradido/pull/270)
- remove links to not work [`#267`](https://github.com/gradido/gradido/pull/267)
- change order of session_id [`#269`](https://github.com/gradido/gradido/pull/269)
- bug: Dynamic Balance [`#260`](https://github.com/gradido/gradido/pull/260)
- Fix problems with transactions in docker environment [`#261`](https://github.com/gradido/gradido/pull/261)
- update skeema call to allow also for unsafe db updates [`#250`](https://github.com/gradido/gradido/pull/250)
- turn registration on and off [`#266`](https://github.com/gradido/gradido/pull/266)
- 243 vue loader component - varante 2 [`#257`](https://github.com/gradido/gradido/pull/257)
- fix_issue_templates [`#262`](https://github.com/gradido/gradido/pull/262)
- fix_nginx_docker [`#253`](https://github.com/gradido/gradido/pull/253)
- 13_coverage [`#255`](https://github.com/gradido/gradido/pull/255)
- add language as fields which will be returned with user-object [`#244`](https://github.com/gradido/gradido/pull/244)
- add short description for target date in creation transaction [`#252`](https://github.com/gradido/gradido/pull/252)
- fix error "Integrity constraint violation: 1052 Column 'id' in where … [`#251`](https://github.com/gradido/gradido/pull/251)
- Clicks on button [`#246`](https://github.com/gradido/gradido/pull/246)
- Change css [`#231`](https://github.com/gradido/gradido/pull/231)
- feat: Reset Password [`#212`](https://github.com/gradido/gradido/pull/212)
- fix bug #221 [`#228`](https://github.com/gradido/gradido/pull/228)
- fix empty reply by empty group_id [`#227`](https://github.com/gradido/gradido/pull/227)
- Bugfix 22 04 21 [`#226`](https://github.com/gradido/gradido/pull/226)
- Rollback use prebuild dependencies [`#225`](https://github.com/gradido/gradido/pull/225)
- Docu [`#199`](https://github.com/gradido/gradido/pull/199)
- update login-server build [`#222`](https://github.com/gradido/gradido/pull/222)
- Login add language [`#220`](https://github.com/gradido/gradido/pull/220)
- User Object on Json Login [`#219`](https://github.com/gradido/gradido/pull/219)
- refactor: Remove loginAPI Call from Store [`#215`](https://github.com/gradido/gradido/pull/215)
- fix: Remove Rules for Password on Login [`#214`](https://github.com/gradido/gradido/pull/214)
- Community 15 04 2021 [`#198`](https://github.com/gradido/gradido/pull/198)
- refactor: Remove Right Menu [`#204`](https://github.com/gradido/gradido/pull/204)
- feat: Raise Frontend Test Coverage to 12% [`#206`](https://github.com/gradido/gradido/pull/206)
- refactor: Remove Cookies [`#202`](https://github.com/gradido/gradido/pull/202)
- fix_docker_compose [`#205`](https://github.com/gradido/gradido/pull/205)
- 62 pwd reset [`#203`](https://github.com/gradido/gradido/pull/203)
- workflows_refactor [`#200`](https://github.com/gradido/gradido/pull/200)
- feat: Link to Whitepaper in Content-Footer [`#196`](https://github.com/gradido/gradido/pull/196)
- update code which produce error which last fix (._.); [`#197`](https://github.com/gradido/gradido/pull/197)
- refactor: Redirects and Misuse of Children in Router [`#194`](https://github.com/gradido/gradido/pull/194)
- fix: Gradido-Akademie in Footer Links to gradido.net [`#170`](https://github.com/gradido/gradido/pull/170)
- fix register [`#160`](https://github.com/gradido/gradido/pull/160)
- Login 14.04.21 [`#175`](https://github.com/gradido/gradido/pull/175)
- coverage_no_report [`#176`](https://github.com/gradido/gradido/pull/176)
- Community 14.04.21 [`#174`](https://github.com/gradido/gradido/pull/174)
- feat: Add Coverage Check To GitHub Workflow [`#158`](https://github.com/gradido/gradido/pull/158)
- Stage2 [`#49`](https://github.com/gradido/gradido/pull/49)
- feat: Unit Test for KontoOverview [`#169`](https://github.com/gradido/gradido/pull/169)
- fix: Remove Hashtag From Route [`#167`](https://github.com/gradido/gradido/pull/167)
- documentation for reset password [`#166`](https://github.com/gradido/gradido/pull/166)
- 90 show release version in frontend [`#153`](https://github.com/gradido/gradido/pull/153)
- docu frontend menu page structur [`#159`](https://github.com/gradido/gradido/pull/159)
- userstorry_button.txt example [`#157`](https://github.com/gradido/gradido/pull/157)
- fix getBalance API call [`#147`](https://github.com/gradido/gradido/pull/147)
- Locale clear list merge master [`#119`](https://github.com/gradido/gradido/pull/119)
- fix-125-link-to-community [`#152`](https://github.com/gradido/gradido/pull/152)
- feat: Test Dashboard Layout [`#154`](https://github.com/gradido/gradido/pull/154)
- feat: Activate Coverage Report For Unit Tests In Frontend [`#156`](https://github.com/gradido/gradido/pull/156)
- Docu [`#120`](https://github.com/gradido/gradido/pull/120)
- Fix compose bug [`#138`](https://github.com/gradido/gradido/pull/138)
- feat: Test Login Form [`#113`](https://github.com/gradido/gradido/pull/113)
- at last, fix email-bug [`#134`](https://github.com/gradido/gradido/pull/134)
- Api password reset [`#82`](https://github.com/gradido/gradido/pull/82)
- Optimize login server build [`#101`](https://github.com/gradido/gradido/pull/101)
- markdown of login server api [`#111`](https://github.com/gradido/gradido/pull/111)
- Fix lineendings [`#112`](https://github.com/gradido/gradido/pull/112)
- Background color change [`#117`](https://github.com/gradido/gradido/pull/117)
- Delete unused files [`#116`](https://github.com/gradido/gradido/pull/116)
- store aufräumen teil 1 [`#115`](https://github.com/gradido/gradido/pull/115)
- add migrations table for automatic table data migration [`40a9a8c`](https://github.com/gradido/gradido/commit/40a9a8c2b587f5bef0fcc54136ed7bd13dd91b2b)
- update yarn.lock after running yarn install [`7f38c80`](https://github.com/gradido/gradido/commit/7f38c801213ad886e9d34a8d43b00ae423f5f2a0)
- use new function for balance overview in old frontend, update balance in session on every php-request [`97c570c`](https://github.com/gradido/gradido/commit/97c570c08cc51ed17a69eb8be8d987f95f3c2ce0)
#### [0.9.4](https://github.com/gradido/gradido/compare/0.9.3...0.9.4)
> 30 March 2021
- Vue with nginx [`#84`](https://github.com/gradido/gradido/pull/84)
- Build on run [`#103`](https://github.com/gradido/gradido/pull/103)
- update debug docker to use dependencies container pushed to docker hub [`1f002f4`](https://github.com/gradido/gradido/commit/1f002f4ed0b12d4b2bf63efceabe546d0c5b58ea)
- removed email tasks complete [`8a143be`](https://github.com/gradido/gradido/commit/8a143be8423d7bd894d4f512848895df8b9694b0)

View File

@ -21,7 +21,7 @@ use Cake\Routing\Router;
use Cake\ORM\TableRegistry;
use Cake\Core\Configure;
use Cake\I18n\Time;
use Cake\I18n\I18n;
use Cake\I18n\FrozenTime;
/**
* Application Controller
@ -174,6 +174,7 @@ class AppController extends Controller
protected function requestLogin($sessionId = 0, $redirect = true)
{
$this->checkForMigration($redirect);
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
$session = $this->getRequest()->getSession();
// check login
// disable encryption for cookies
@ -206,12 +207,15 @@ class AppController extends Controller
$transactionPendings = $session->read('Transactions.pending');
$transactionExecutings = $session->read('Transactions.executing');
$transaction_can_signed = $session->read('Transactions.can_signed');
if ($session->read('session_id') != $session_id ||
( $userStored && (!isset($userStored['id']) || !$userStored['email_checked'])) ||
intval($transactionPendings) > 0 ||
intval($transactionExecutings) > 0 ||
intval($transaction_can_signed > 0)) {
intval($transaction_can_signed > 0))
{
$http = new Client();
try {
@ -242,6 +246,7 @@ class AppController extends Controller
$session->write('Transactions.can_signed', $transaction_can_signed);
$session->write('session_id', $session_id);
$stateUserTable = TableRegistry::getTableLocator()->get('StateUsers');
if (isset($json['user']['public_hex']) && $json['user']['public_hex'] != '') {
$public_key_bin = hex2bin($json['user']['public_hex']);
@ -270,11 +275,6 @@ class AppController extends Controller
$this->Flash->error(__('error updating state user ' . json_encode($stateUser->errors())));
}
}
//var_dump($stateUser);
if (count($stateUser->state_balances) > 0) {
$session->write('StateUser.balance', $stateUser->state_balances[0]->decay);
}
$session->write('StateUser.id', $stateUser->id);
//echo $stateUser['id'];
} else {
@ -326,6 +326,11 @@ class AppController extends Controller
//continue;
}
}
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $session->read('StateUser.id')])->first();
if ($state_balance) {
$now = new FrozenTime;
$session->write('StateUser.balance', $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now));
}
} else {
// no login
//die("no login");

View File

@ -360,7 +360,7 @@ class AppRequestsController extends AppController
$body['decay'] = 0.0;
} else {
$body['balance'] = $state_balance->amount;
$body['decay'] = $state_balance->partDecay($now);
$body['decay'] = $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now);
}
$this->set('body', $body);

View File

@ -64,6 +64,7 @@ class MigrationsController extends AppController
$commands = [
[$blockchainTypesTable, 'fillWithDefault'],
[$transactionTypesTable, 'fillWithDefault'],
[$stateBalancesTable, 'truncate'],
[$transactionsTable, 'fillStateUserTransactions'],
[$stateBalancesTable, 'updateAllBalances']
];

View File

@ -2,7 +2,7 @@
namespace App\Controller;
use Cake\ORM\TableRegistry;
use Cake\I18n\Time;
use Cake\I18n\FrozenTime;
use Model\Navigation\NaviHierarchy;
use Model\Navigation\NaviHierarchyEntry;
@ -65,6 +65,7 @@ class StateBalancesController extends AppController
if($update_balance_result['success'] !== true) {
$this->addAdminError('StateBalances', 'overview', $update_balance_result, $user['id']);
}
// sendRequestGDT
// listPerEmailApi
@ -84,200 +85,68 @@ class StateBalancesController extends AppController
//}
//
//
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
$creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
$creationTransactions = $creationsTable
->find('all')
->where(['state_user_id' => $user['id']])
->contain(['Transactions']);
$transferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
$transferTransactions = $transferTable
->find('all')
->where(['OR' => ['state_user_id' => $user['id'], 'receiver_user_id' => $user['id']]])
->contain(['Transactions']);
$involvedUserIds = [];
foreach ($transferTransactions as $sendCoins) {
//var_dump($sendCoins);
if ($sendCoins->state_user_id != $user['id']) {
array_push($involvedUserIds, intval($sendCoins->state_user_id));
} elseif ($sendCoins->receiver_user_id != $user['id']) {
array_push($involvedUserIds, intval($sendCoins->receiver_user_id));
}
}
/*echo "state user from sendCoins: $sendCoins->state_user_id<br>";
echo "receiver user from sendCoins: $sendCoins->receiver_user_id<br>";
echo "user id from logged in user: ".$user['id']. '<br>';
*/
//var_dump($involvedUserIds);
// exchange key with values and drop duplicates
$involvedUser_temp = array_flip($involvedUserIds);
// exchange back
$involvedUserIds = array_flip($involvedUser_temp);
$userTable = TableRegistry::getTableLocator()->get('StateUsers');
$involvedUser = $userTable->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;
}
// sender or receiver when user has sended money
// group name if creation
// type: gesendet / empfangen / geschöpft
// transaktion nr / id
// date
// balance
$transactions = [];
foreach ($creationTransactions as $creation) {
//var_dump($creation);
array_push($transactions, [
'name' => 'Gradido Akademie',
'type' => 'creation',
'transaction_id' => $creation->transaction_id,
'date' => $creation->target_date,
'balance' => $creation->amount,
'memo' => $creation->transaction->memo
]);
}
foreach ($transferTransactions as $sendCoins) {
$type = '';
$otherUser = null;
$other_user_public = '';
if ($sendCoins->state_user_id == $user['id']) {
$type = 'send';
if(isset($involvedUserIndices[$sendCoins->receiver_user_id])) {
$otherUser = $involvedUserIndices[$sendCoins->receiver_user_id];
}
$other_user_public = bin2hex(stream_get_contents($sendCoins->receiver_public_key));
} else if ($sendCoins->receiver_user_id == $user['id']) {
$type = 'receive';
if(isset($involvedUserIndices[$sendCoins->state_user_id])) {
$otherUser = $involvedUserIndices[$sendCoins->state_user_id];
}
if($sendCoins->sender_public_key) {
$other_user_public = bin2hex(stream_get_contents($sendCoins->sender_public_key));
}
}
if(null == $otherUser) {
$otherUser = $this->StateBalances->StateUsers->newEntity();
}
array_push($transactions, [
'name' => $otherUser->first_name . ' ' . $otherUser->last_name,
'email' => $otherUser->email,
'type' => $type,
'transaction_id' => $sendCoins->transaction_id,
'date' => $sendCoins->transaction->received,
'balance' => $sendCoins->amount,
'memo' => $sendCoins->transaction->memo,
'pubkey' => $other_user_public
]);
}
uasort($transactions, array($this, 'sortTransactions'));
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
// add decay transactions
$month_start_state_balance = null;
$current_state_balance = null;
$cursor = 0;
$transactions_reversed = array_reverse($transactions);
$decay_transactions = [];
$maxI = count($transactions_reversed);
$stateBalancesTable->updateBalances($user['id']);
foreach($transactions_reversed as $i => $transaction) {
if(!isset($transaction['transaction_id'])) {
//echo "missing transaction<br>";
continue;
}
$transaction_id = $transaction['transaction_id'];
//echo "transaction id: $transaction_id <br>";
$decay_transaction = NULL;
$state_balance = $this->StateBalances->newEntity();
if($i > 0 && isset($transactions_reversed[$i-1]['transaction_id'])) {
$prev_transaction = $transactions_reversed[$i-1];
$stateUserTransactions = $stateUserTransactionsTable
->find()
->where([
'transaction_id IN' => [$transaction_id, $prev_transaction['transaction_id']],
'state_user_id' => $user['id']
])
->order(['balance_date ASC'])
->toArray();
$prev = $stateUserTransactions[0];
if($prev->balance > 0) {
// var_dump($stateUserTransactions);
$current = $stateUserTransactions[1];
//echo "decay between " . $prev->transaction_id . " and " . $current->transaction_id . "<br>";
$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);
//echo $interval->format('%R%a days');
//echo "prev balance: " . $prev->balance . ", diff_amount: $diff_amount, summe: " . (-intval($prev->balance - $diff_amount)) . "<br>";
$decay_transaction = [
'type' => 'decay',
'balance' => -intval($prev->balance - $diff_amount),
'decay_duration' => $interval->format('%a days, %H hours, %I minutes, %S seconds'),
'memo' => ''
];
}
}
if($decay_transaction) {
$decay_transactions[] = $decay_transaction;
//array_splice($transactions_reversed, $i + $cursor, 0, [$decay_transaction]);
//$cursor++;
}
if($i == $maxI-1) {
$stateUserTransaction = $stateUserTransactionsTable
->find()
->where(['transaction_id' => $transaction_id, 'state_user_id' => $user['id']])
->order(['transaction_id ASC'])->first();
//var_dump($stateUserTransaction);
$state_balance->amount = $stateUserTransaction->balance;
$state_balance->record_date = $stateUserTransaction->balance_date;
$decay_transactions[] = [
//$transactions_reversed[] = [
'type' => 'decay',
'balance' => -intval($stateUserTransaction->balance - $state_balance->decay),
'decay_duration' => $stateUserTransaction->balance_date->timeAgoInWords(),
'memo' => ''
];
}
$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 {
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id'] ? $user['id'] : 0);
}
$final_transactions = [];
foreach($transactions_reversed as $i => $transaction) {
$final_transactions[] = $transaction;
$final_transactions[] = $decay_transactions[$i];
$stateUserTransactionsQuery = $stateUserTransactionsTable
->find()
->where(['state_user_id' => $user['id']])
->order(['balance_date' => 'ASC'])
->contain([])
;
$decay = true;
$transactions = [];
if($stateUserTransactionsQuery->count() > 0) {
$transactions = $transactionsTable->listTransactionsHumanReadable($stateUserTransactionsQuery->toArray(), $user, $decay);
}
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $user['id']])->first();
$body = [
'state' => 'success',
'transactions' => $transactions,
'transactionExecutingCount' => $session->read('Transactions.executing'),
'count' => count($transactions),
'gdtSum' => $gdtSum,
'timeUsed' => microtime(true) - $startTime
];
$now = new FrozenTime();
$body['decay_date'] = $now;
if(!$state_balance) {
$balance = 0.0;
} else {
$balance = $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now);
//$balance = $state_balance->partDecay($now);
}
// for debugging
$calculated_balance = 0;
foreach($final_transactions as $tr) {
if($tr['type'] == 'send') {
$calculated_balance -= intval($tr['balance']);
foreach($transactions as $transaction) {
if($transaction['type'] == 'decay' || $transaction['type'] == 'send') {
$calculated_balance -= $transaction['balance'];
} else {
$calculated_balance += intval($tr['balance']);
$calculated_balance += $transaction['balance'];
}
}
$this->set('calculated_balance', $calculated_balance);
$this->set('transactions', array_reverse($final_transactions));
$this->set('transactions', array_reverse($transactions));
$this->set('transactionExecutingCount', $session->read('Transactions.executing'));
$this->set('balance', $session->read('StateUser.balance'));
$this->set('balance', $balance);
$this->set('timeUsed', microtime(true) - $startTime);
$this->set('gdtSum', $gdtSum);
}
@ -301,151 +170,16 @@ class StateBalancesController extends AppController
if(!$state_balance) {
return $this->returnJson(['state' => 'success', 'balance' => 0]);
}
$now = new FrozenTime();
return $this->returnJson([
'state' => 'success',
'balance' => $state_balance->amount,
'decay' => $state_balance->decay
'decay' => $this->StateBalances->calculateDecay($state_balance->amount, $state_balance->record_date, $now),
'decay_date' => $now
]);
}
public function ajaxListTransactions($session_id, $page=1, $count=25)
{
if(!$session_id) {
return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']);
}
$startTime = microtime(true);
$login_result = $this->requestLogin($session_id, false);
if($login_result !== true) {
return $this->returnJson($login_result);
}
$session = $this->getRequest()->getSession();
$user = $session->read('StateUser');
$this->StateBalances->updateBalances($user['id']);
$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) {
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id']);
} else {
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, 0);
}
}
$creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
$creationTransactions = $creationsTable
->find('all')
->where(['state_user_id' => $user['id']])
->contain(['Transactions']);
$transferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
$transferTransactions = $transferTable
->find('all')
->where(['OR' => ['state_user_id' => $user['id'], 'receiver_user_id' => $user['id']]])
->contain(['Transactions']);
$involvedUserIds = [];
foreach ($transferTransactions as $sendCoins) {
//var_dump($sendCoins);
if ($sendCoins->state_user_id != $user['id']) {
array_push($involvedUserIds, intval($sendCoins->state_user_id));
} elseif ($sendCoins->receiver_user_id != $user['id']) {
array_push($involvedUserIds, intval($sendCoins->receiver_user_id));
}
}
/*echo "state user from sendCoins: $sendCoins->state_user_id<br>";
echo "receiver user from sendCoins: $sendCoins->receiver_user_id<br>";
echo "user id from logged in user: ".$user['id']. '<br>';
*/
//var_dump($involvedUserIds);
// exchange key with values and drop duplicates
$involvedUser_temp = array_flip($involvedUserIds);
// exchange back
$involvedUserIds = array_flip($involvedUser_temp);
$userTable = TableRegistry::getTableLocator()->get('StateUsers');
$involvedUser = $userTable->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;
}
// sender or receiver when user has sended money
// group name if creation
// type: gesendet / empfangen / geschöpft
// transaktion nr / id
// date
// balance
$transactions = [];
foreach ($creationTransactions as $creation) {
//var_dump($creation);
array_push($transactions, [
'name' => 'Gradido Akademie',
'type' => 'creation',
'transaction_id' => $creation->transaction_id,
'date' => $creation->transaction->received,
'balance' => $creation->amount,
'memo' => $creation->transaction->memo
]);
}
foreach ($transferTransactions as $sendCoins) {
$type = '';
$otherUser = null;
if ($sendCoins->state_user_id == $user['id']) {
$type = 'send';
if(isset($involvedUserIndices[$sendCoins->receiver_user_id])) {
$otherUser = $involvedUserIndices[$sendCoins->receiver_user_id];
}
} else if ($sendCoins->receiver_user_id == $user['id']) {
$type = 'receive';
if(isset($involvedUserIndices[$sendCoins->state_user_id])) {
$otherUser = $involvedUserIndices[$sendCoins->state_user_id];
}
}
if(null == $otherUser) {
$otherUser = $this->StateBalances->StateUsers->newEntity();
}
array_push($transactions, [
'name' => $otherUser->first_name . ' ' . $otherUser->last_name,
'email' => $otherUser->email,
'type' => $type,
'transaction_id' => $sendCoins->transaction_id,
'date' => $sendCoins->transaction->received,
'balance' => $sendCoins->amount,
'memo' => $sendCoins->transaction->memo
]);
}
uasort($transactions, array($this, 'sortTransactions'));
if($sort == 'DESC') {
$transactions = array_reverse($transactions);
}
return $this->returnJson([
'state' => 'success',
'transactions' => $transactions,
'transactionExecutingCount' => $session->read('Transactions.executing'),
'count' => count($transactions),
'gdtSum' => $gdtSum,
'timeUsed' => microtime(true) - $startTime
]);
}
public function ajaxGdtOverview()
{

View File

@ -22,6 +22,7 @@ class AppTable extends Table
$this->getConnection()->query($truncateCommand);
}
$this->getConnection()->query('ALTER TABLE ' . $this->getSchema()->name() . ' AUTO_INCREMENT=1');
return ['success' => true];
}
public function saveManyWithErrors($entities)
{

View File

@ -24,7 +24,7 @@ use Cake\I18n\FrozenTime;
*
* @mixin \Cake\ORM\Behavior\TimestampBehavior
*/
class StateBalancesTable extends Table
class StateBalancesTable extends AppTable
{
private static $startDecayDate = null;
/**

View File

@ -426,6 +426,9 @@ class TransactionsTable extends Table
}
}
}
if(count($state_user_ids) < 1) {
return ['success' => true];
}
//var_dump($entities);
$stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers');
$existingStateUsers = $stateUsersTable->find('all')->select(['id'])->where(['id IN' => $state_user_ids])->order(['id'])->all();

View File

@ -1,6 +1,6 @@
{
"name": "bootstrap-vue-gradido-wallet",
"version": "0.9.4",
"version": "1.0.1",
"private": true,
"scripts": {
"start": "node run/server.js",

View File

@ -1,20 +1,5 @@
<template>
<div id="app" class="font-sans text-gray-800">
<header>
<b-col class="text-center">
<b-dropdown
size="sm"
split
variant="secondary"
:text="$t('language') + ' - ' + $i18n.locale"
class="m-md-2"
>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item @click.prevent="setLocale('de')">Deutsch</b-dropdown-item>
<b-dropdown-item @click.prevent="setLocale('en')">English</b-dropdown-item>
</b-dropdown>
</b-col>
</header>
<div class="">
<particles-bg type="custom" :config="config" :bg="true" />
<component :is="$route.meta.requiresAuth ? 'DashboardLayout' : 'AuthLayoutGDD'" />
@ -25,7 +10,6 @@
<script>
import { ParticlesBg } from 'particles-bg-vue'
import icon from './icon.js'
import { localeChanged } from 'vee-validate'
import DashboardLayout from '@/views/Layout/DashboardLayout_gdd.vue'
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
@ -54,13 +38,6 @@ export default {
},
}
},
methods: {
setLocale(locale) {
this.$i18n.locale = locale
this.$store.commit('language', this.$i18n.locale)
localeChanged(locale)
},
},
}
</script>
<style>

View File

@ -51,14 +51,11 @@ const communityAPI = {
}
return apiPost(CONFIG.COMMUNITY_API__URL + 'createCoins/', payload)
}, */
send: async (sessionId, email, amount, memo, targetDate) => {
send: async (sessionId, data) => {
const payload = {
session_id: sessionId,
email,
amount,
memo,
target_date: targetDate,
auto_sign: true,
...data,
}
return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload)
},

View File

@ -0,0 +1,22 @@
<template>
<div class="language-switch">
<b-dropdown size="sm" :text="$t('language') + ' - ' + $i18n.locale">
<b-dropdown-item @click.prevent="setLocale('de')">Deutsch</b-dropdown-item>
<b-dropdown-item @click.prevent="setLocale('en')">English</b-dropdown-item>
</b-dropdown>
</div>
</template>
<script>
import { localeChanged } from 'vee-validate'
export default {
name: 'language-switch',
methods: {
setLocale(locale) {
this.$i18n.locale = locale
this.$store.commit('language', this.$i18n.locale)
localeChanged(locale)
},
},
}
</script>

View File

@ -0,0 +1,123 @@
import { mount, RouterLinkStub } from '@vue/test-utils'
import SideBar from './SideBar'
const localVue = global.localVue
describe('SideBar', () => {
let wrapper
const stubs = {
RouterLink: RouterLinkStub,
}
const propsData = {
balance: 1234.56,
}
const mocks = {
$store: {
state: {
email: 'test@example.org',
},
},
$i18n: {
locale: 'en',
},
$t: jest.fn((t) => t),
$n: jest.fn((n) => n),
}
const Wrapper = () => {
return mount(SideBar, { localVue, mocks, stubs, propsData })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders the component', () => {
expect(wrapper.find('#sidenav-main').exists()).toBeTruthy()
})
describe('balance', () => {
it('shows em-dash as balance while loading', () => {
expect(wrapper.find('div.row.text-center').text()).toBe('— GDD')
})
it('shows the when loaded', async () => {
wrapper.setProps({
pending: false,
})
await wrapper.vm.$nextTick()
expect(wrapper.find('div.row.text-center').text()).toBe('1234.56 GDD')
})
})
describe('navbar button', () => {
it('has a navbar button', () => {
expect(wrapper.find('button.navbar-toggler').exists()).toBeTruthy()
})
it('calls showSidebar when clicked', async () => {
const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar')
wrapper.find('button.navbar-toggler').trigger('click')
await wrapper.vm.$nextTick()
expect(spy).toHaveBeenCalledWith(true)
})
})
describe('close siedbar', () => {
it('calls closeSidebar when clicked', async () => {
const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar')
wrapper.find('#sidenav-collapse-main').find('button.navbar-toggler').trigger('click')
await wrapper.vm.$nextTick()
expect(spy).toHaveBeenCalledWith(false)
})
})
describe('static menu items', () => {
describe("member's area", () => {
it('has a link to the elopage', () => {
expect(wrapper.findAll('li').at(0).text()).toBe('members_area')
})
it('links to the elopage', () => {
expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe(
'https://elopage.com/s/gradido/sign_in?locale=en',
)
})
describe('with locale="de"', () => {
beforeEach(() => {
mocks.$i18n.locale = 'de'
})
it('links to the German elopage when locale is set to de', () => {
expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe(
'https://elopage.com/s/gradido/sign_in?locale=de',
)
})
})
})
describe('logout', () => {
it('has a logout button', () => {
expect(wrapper.findAll('li').at(1).text()).toBe('logout')
})
it('emits logout when logout is clicked', async () => {
wrapper.findAll('li').at(1).find('a').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.emitted('logout')).toEqual([[]])
})
})
describe('language-switch', () => {
it('has a language-switch button', () => {
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
})
})
})
})
})

View File

@ -10,7 +10,7 @@
<img :src="logo" class="navbar-brand-img" alt="..." />
</div>
<b-row class="text-center">
<b-col>{{ $n(balance) }} GDD</b-col>
<b-col>{{ pending ? '—' : $n(balance) }} GDD</b-col>
</b-row>
<slot name="mobile-right">
<ul class="nav align-items-center d-md-none">
@ -32,9 +32,7 @@
<div class="navbar-collapse-header d-md-none">
<div class="row">
<div class="col-6 collapse-brand">
<router-link to="/overview">
<img :src="logo" />
</router-link>
<img :src="logo" />
</div>
<div class="col-6 collapse-close">
<navbar-toggle-button @click.native="closeSidebar"></navbar-toggle-button>
@ -44,26 +42,29 @@
<ul class="navbar-nav">
<slot name="links"></slot>
</ul>
<hr class="my-3" />
<ul class="navbar-nav mb-md-3">
<hr class="my-2" />
<ul class="navbar-nav ml-3">
<li class="nav-item">
<a
:href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
class="nav-link text-lg"
class="nav-link"
target="_blank"
>
{{ $t('members_area') }}
</a>
</li>
</ul>
<hr class="my-3" />
<ul class="navbar-nav mb-md-3">
<ul class="navbar-nav ml-3">
<li class="nav-item">
<a class="nav-link text-lg pointer" @click="logout">
<a class="nav-link pointer" @click="logout">
{{ $t('logout') }}
</a>
</li>
</ul>
<div class="mt-5 ml-4">
<language-switch />
</div>
</div>
</div>
</nav>
@ -71,12 +72,14 @@
<script>
import NavbarToggleButton from '@/components/NavbarToggleButton'
import VueQrcode from 'vue-qrcode'
import LanguageSwitch from '@/components/LanguageSwitch.vue'
export default {
name: 'sidebar',
components: {
NavbarToggleButton,
VueQrcode,
LanguageSwitch,
},
props: {
logo: {
@ -93,6 +96,10 @@ export default {
type: Number,
default: 0,
},
pending: {
type: Boolean,
default: true,
},
},
provide() {
return {

View File

@ -57,7 +57,6 @@
},
"transaction":{
"show_all":"View all <strong>{count}</strong> transactions.",
"show_part": "The last <strong>{count}</strong> transactions.",
"nullTransactions":"You don't have any transactions on your account yet.",
"more": "more"
},

View File

@ -1,16 +1,19 @@
<template>
<div class="wrapper">
<div class="main-content">
<div class="main-content mt-4">
<router-view></router-view>
<language-switch class="text-center mb-5 mt-5" />
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
</div>
</div>
</template>
<script>
import ContentFooter from './ContentFooter.vue'
import LanguageSwitch from '@/components/LanguageSwitch.vue'
export default {
components: {
ContentFooter,
LanguageSwitch,
},
}
</script>

View File

@ -59,10 +59,6 @@ describe('DashboardLayoutGdd', () => {
expect(wrapper.find('nav#sidenav-main').exists()).toBeTruthy()
})
it('has a notifications component', () => {
expect(wrapper.find('div.notifications').exists()).toBeTruthy()
})
it('has a main content div', () => {
expect(wrapper.find('div.main-content').exists()).toBeTruthy()
})
@ -79,31 +75,35 @@ describe('DashboardLayoutGdd', () => {
})
it('has five items in the navbar', () => {
expect(navbar.findAll('ul > li')).toHaveLength(2)
expect(navbar.findAll('ul > a')).toHaveLength(2)
})
it('has first item "send" in navbar', () => {
expect(navbar.findAll('ul > li').at(0).text()).toEqual('send')
expect(navbar.findAll('ul > a').at(0).text()).toEqual('send')
})
it('has first item "send" linked to overview in navbar', () => {
navbar.findAll('ul > li').at(0).trigger('click')
navbar.findAll('ul > a').at(0).trigger('click')
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/overview')
})
it('has second item "transactions" in navbar', () => {
expect(navbar.findAll('ul > li').at(1).text()).toEqual('transactions')
expect(navbar.findAll('ul > a').at(1).text()).toEqual('transactions')
})
// to do: get this working!
it.skip('has second item "transactions" linked to transactions in navbar', async () => {
navbar.findAll('ul > li > a').at(1).trigger('click')
navbar.findAll('ul > a').at(1).trigger('click')
await flushPromises()
await jest.runAllTimers()
await flushPromises()
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/transactions')
})
// it('has tree items in the navbar', () => {
// expect(navbar.findAll('ul > li')).toHaveLength(3)
// })
//
// it('has third item "My profile" in navbar', () => {
// expect(navbar.findAll('ul > li').at(2).text()).toEqual('site.navbar.my-profil')
// })

View File

@ -1,30 +1,35 @@
<template>
<div class="wrapper">
<notifications></notifications>
<side-bar @logout="logout" :balance="balance">
<side-bar @logout="logout" :balance="balance" :pending="pending">
<template slot="links">
<b-nav-item href="#!" to="/overview">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('send') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/transactions">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('transactions') }}</b-nav-text>
</b-nav-item>
<sidebar-item
:link="{
name: $t('send'),
path: '/overview',
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('transactions'),
path: '/transactions',
}"
></sidebar-item>
<!--
<b-nav-item href="#!" to="/profile">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/profileedit">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/activity">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/profile">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/profileedit">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/activity">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
</b-nav-item>
-->
</template>
</side-bar>
<div class="main-content">
<dashboard-navbar :type="$route.meta.navbarType"></dashboard-navbar>
<div @click="$sidebar.displaySidebar(false)">
<fade-transition :duration="200" origin="center top" mode="out-in">
<!-- your content here -->
@ -33,6 +38,7 @@
:gdt-balance="GdtBalance"
:transactions="transactions"
:transactionCount="transactionCount"
:pending="pending"
@update-balance="updateBalance"
@update-transactions="updateTransactions"
></router-view>
@ -83,6 +89,7 @@ export default {
transactions: [],
bookedBalance: 0,
transactionCount: 0,
pending: true,
}
},
methods: {
@ -99,6 +106,7 @@ export default {
this.$router.push('/login')
},
async updateTransactions() {
this.pending = true
const result = await communityAPI.transactions(this.$store.state.sessionId)
if (result.success) {
this.GdtBalance = Number(result.result.data.gdtSum)
@ -106,7 +114,9 @@ export default {
this.balance = Number(result.result.data.decay)
this.bookedBalance = Number(result.result.data.balance)
this.transactionCount = result.result.data.count
this.pending = false
} else {
this.pending = true
// what to do when loading balance fails?
}
},

View File

@ -10,7 +10,7 @@
<li class="nav-item d-sm-none"></li>
</b-navbar-nav>
<b-navbar-nav class="align-items-center ml-auto ml-md-0">
<a class="pr-1 nav-link" slot="title-container pointer">
<div class="pr-1" slot="title-container ">
<b-media no-body class="align-items-center">
<span class="pb-2 text-lg font-weight-bold">
{{ $store.state.email }}
@ -21,7 +21,7 @@
</span>
</b-media-body>
</b-media>
</a>
</div>
</b-navbar-nav>
</base-nav>
</template>

View File

@ -34,30 +34,5 @@ describe('AccountOverview', () => {
it('has a transactions table', () => {
expect(wrapper.find('gdd-table-stub').exists()).toBeTruthy()
})
describe('updateBalance method', () => {
beforeEach(async () => {
wrapper.find('gdd-send-stub').vm.$emit('update-balance', {
ammount: 42,
})
await wrapper.vm.$nextTick()
})
it('emmits updateBalance with correct value', () => {
expect(wrapper.emitted('update-balance')).toEqual([[42]])
})
})
describe('toggleShowList method', () => {
beforeEach(async () => {
wrapper.setProps({ showTransactionList: false })
wrapper.find('gdd-send-stub').vm.$emit('toggle-show-list', true)
await wrapper.vm.$nextTick()
})
it('changes the value of property showTransactionList', () => {
expect(wrapper.vm.showTransactionList).toBeTruthy()
})
})
})
})

View File

@ -1,25 +1,43 @@
<template>
<div>
<base-header class="pb-4 pt-2 bg-transparent"></base-header>
<b-container fluid class="p-2 mt-5">
<gdd-status v-if="showTransactionList" :balance="balance" :gdt-balance="GdtBalance" />
<br />
<gdd-send
<base-header class="pb-lg-4 pt-lg-2 bg-transparent"></base-header>
<b-container fluid class="p-lg-2 mt-lg-5">
<gdd-status
v-if="showContext"
:pending="pending"
:balance="balance"
:show-transaction-list="showTransactionList"
@update-balance="updateBalance"
@toggle-show-list="toggleShowList"
:gdt-balance="GdtBalance"
/>
<br />
<gdd-send :currentTransactionStep="currentTransactionStep">
<template #transaction-form>
<transaction-form :balance="balance" @set-transaction="setTransaction"></transaction-form>
</template>
<template #transaction-confirmation>
<transaction-confirmation
:email="transactionData.email"
:amount="transactionData.amount"
:memo="transactionData.memo"
:date="transactionData.target_date"
:loading="loading"
@send-transaction="sendTransaction"
@on-reset="onReset"
></transaction-confirmation>
</template>
<template #transaction-result>
<transaction-result :error="error" @on-reset="onReset"></transaction-result>
</template>
</gdd-send>
<hr />
<gdd-table
v-if="showTransactionList"
v-if="showContext"
:transactions="transactions"
:max="5"
:timestamp="timestamp"
:transactionCount="transactionCount"
@update-transactions="updateTransactions"
@update-transactions="$emit('update-transactions')"
/>
<gdd-table-footer :count="transactionCount" />
<gdd-table-footer v-if="showContext" :count="transactionCount" />
</b-container>
</div>
</template>
@ -28,6 +46,17 @@ import GddStatus from './AccountOverview/GddStatus.vue'
import GddSend from './AccountOverview/GddSend.vue'
import GddTable from './AccountOverview/GddTable.vue'
import GddTableFooter from './AccountOverview/GddTableFooter.vue'
import TransactionForm from './AccountOverview/GddSend/TransactionForm.vue'
import TransactionConfirmation from './AccountOverview/GddSend/TransactionConfirmation.vue'
import TransactionResult from './AccountOverview/GddSend/TransactionResult.vue'
import communityAPI from '../../apis/communityAPI.js'
const EMPTY_TRANSACTION_DATA = {
email: '',
amount: 0,
memo: '',
target_date: '',
}
export default {
name: 'Overview',
@ -36,11 +65,17 @@ export default {
GddSend,
GddTable,
GddTableFooter,
TransactionForm,
TransactionConfirmation,
TransactionResult,
},
data() {
return {
showTransactionList: true,
timestamp: Date.now(),
transactionData: EMPTY_TRANSACTION_DATA,
error: false,
currentTransactionStep: 0,
loading: false,
}
},
props: {
@ -50,16 +85,37 @@ export default {
default: () => [],
},
transactionCount: { type: Number, default: 0 },
pending: {
type: Boolean,
default: true,
},
},
computed: {
showContext() {
return this.currentTransactionStep === 0
},
},
methods: {
toggleShowList(bool) {
this.showTransactionList = bool
setTransaction(data) {
data.target_date = new Date(Date.now()).toISOString()
this.transactionData = { ...data }
this.currentTransactionStep = 1
},
updateBalance(data) {
this.$emit('update-balance', data.ammount)
async sendTransaction() {
this.loading = true
const result = await communityAPI.send(this.$store.state.sessionId, this.transactionData)
if (result.success) {
this.error = false
this.$emit('update-balance', this.transactionData.amount)
} else {
this.error = true
}
this.currentTransactionStep = 2
this.loading = false
},
updateTransactions() {
this.$emit('update-transactions')
onReset() {
this.transactionData = EMPTY_TRANSACTION_DATA
this.currentTransactionStep = 0
},
},
}

View File

@ -1,29 +1,18 @@
import { mount } from '@vue/test-utils'
import GddSend from './GddSend'
import Vuex from 'vuex'
const localVue = global.localVue
describe('GddSend', () => {
let wrapper
const state = {
user: {
balance: 1234,
balance_gdt: 9876,
},
}
const store = new Vuex.Store({
state,
})
const mocks = {
// $n: jest.fn((n) => n),
$t: jest.fn((t) => t),
$moment: jest.fn((m) => ({
format: () => m,
})),
$store: {
state: {
sessionId: 1234,
},
},
$i18n: {
locale: jest.fn(() => 'en'),
},
@ -31,7 +20,7 @@ describe('GddSend', () => {
}
const Wrapper = () => {
return mount(GddSend, { localVue, store, mocks })
return mount(GddSend, { localVue, mocks })
}
describe('mount', () => {
@ -42,88 +31,5 @@ describe('GddSend', () => {
it('renders the component', () => {
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
})
describe('warning messages', () => {
it('has a warning message', () => {
expect(wrapper.find('div.alert-default').find('span').text()).toBe('form.attention')
})
})
describe('transaction form', () => {
describe('email field', () => {
it('has an input field of type email', () => {
expect(wrapper.find('#input-group-1').find('input').attributes('type')).toBe('email')
})
it('has an envelope icon', () => {
expect(wrapper.find('#input-group-1').find('svg').attributes('aria-label')).toBe(
'envelope',
)
})
it('has a label form.receiver', () => {
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
})
it('has a placeholder "E-Mail"', () => {
expect(wrapper.find('#input-group-1').find('input').attributes('placeholder')).toBe(
'E-Mail',
)
})
})
describe('ammount field', () => {
it('has an input field of type number', () => {
expect(wrapper.find('#input-group-2').find('input').attributes('type')).toBe('number')
})
it('has an GDD text icon', () => {
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
})
it('has a label form.amount', () => {
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
})
it('has a placeholder "0.01"', () => {
expect(wrapper.find('#input-group-2').find('input').attributes('placeholder')).toBe(
'0.01',
)
})
})
describe('message text box', () => {
it('has an textarea field', () => {
expect(wrapper.find('#input-group-3').find('textarea').exists()).toBeTruthy()
})
it('has an chat-right-text icon', () => {
expect(wrapper.find('#input-group-3').find('svg').attributes('aria-label')).toBe(
'chat right text',
)
})
it('has a label form.memo', () => {
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
})
})
describe('cancel button', () => {
it('has a cancel button', () => {
expect(wrapper.find('button[type="reset"]').exists()).toBeTruthy()
})
it('has the text "form.cancel"', () => {
expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset')
})
it.skip('clears the email field on click', async () => {
wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv')
wrapper.find('button[type="reset"]').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.vm.form.email).toBeNull()
})
})
})
})
})

View File

@ -1,346 +1,18 @@
<template>
<div class="gdd-send">
<b-row v-show="showTransactionList">
<b-col xl="12" md="12">
<b-alert show dismissible variant="default" class="text-center">
<span class="alert-text h3 text-light" v-html="$t('form.attention')"></span>
</b-alert>
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
<!--
<b-alert show variant="secondary">
<span class="alert-text" v-html="$t('form.scann_code')"></span>
<b-col v-show="!scan" lg="12" class="text-right">
<a @click="toggle" class="nav-link pointer">
<img src="img/icons/gradido/qr-scan-pure.png" height="50" />
</a>
</b-col>
<div v-if="scan">
<b-row>
<qrcode-capture @detect="onDetect" capture="user" ></qrcode-capture>
</b-row>
<qrcode-stream class="mt-3" @decode="onDecode" @detect="onDetect"></qrcode-stream>
<b-container>
<b-row>
<b-col lg="8">
<b-alert show variant="secondary">
<span class="alert-text" v-html="$t('form.scann_code')"></span>
</b-alert>
</b-col>
</b-row>
</b-container>
</div>
<div @click="toggle">
<b-alert v-show="scan" show variant="primary" class="pointer text-center">
<span class="alert-text">
<strong>{{ $t('form.cancel') }}</strong>
</span>
</b-alert>
</div>
</b-alert>
-->
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
<b-form
role="form"
@submit.prevent="handleSubmit(onSubmit)"
@reset="onReset"
v-if="show"
>
<!-- <div>
<qrcode-drop-zone id="input-0" v-model="form.img"></qrcode-drop-zone>
</div>
<br />
-->
<div>
<validation-provider
name="Email"
:rules="{
required: true,
email: true,
is_not: $store.state.email,
}"
v-slot="{ errors }"
>
<b-row>
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
<b-col v-if="errors" class="text-right p-3 p-sm-1">
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
</b-col>
</b-row>
<b-input-group
id="input-group-1"
label="Empfänger:"
label-for="input-1"
description="We'll never share your email with anyone else."
size="lg"
class="mb-3"
>
<b-input-group-prepend class="p-3 d-none d-md-block">
<b-icon icon="envelope" class="display-3"></b-icon>
</b-input-group-prepend>
<b-form-input
id="input-1"
v-model="form.email"
type="email"
placeholder="E-Mail"
style="font-size: xx-large; padding-left: 20px"
></b-form-input>
</b-input-group>
</validation-provider>
</div>
<br />
<div>
<validation-provider
:name="$t('form.amount')"
:rules="{
required: true,
double: [2, $i18n.locale === 'de' ? ',' : '.'],
between: [0.01, balance],
}"
v-slot="{ errors }"
>
<b-row>
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
<b-col v-if="errors" class="text-right p-3 p-sm-1">
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
</b-col>
</b-row>
<b-input-group
id="input-group-2"
label="Betrag:"
label-for="input-2"
size="lg"
class="mb-3"
>
<b-input-group-prepend class="p-2 d-none d-md-block">
<div class="h3 pt-3 pr-3">GDD</div>
</b-input-group-prepend>
<b-form-input
id="input-2"
v-model="form.amount"
type="number"
:lang="$i18n.locale"
:placeholder="$n(0.01)"
step="0.01"
style="font-size: xx-large; padding-left: 20px"
></b-form-input>
</b-input-group>
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
<b-input-group id="input-group-3">
<b-input-group-prepend class="p-3 d-none d-md-block">
<b-icon icon="chat-right-text" class="display-3"></b-icon>
</b-input-group-prepend>
<b-form-textarea
rows="3"
v-model="form.memo"
class="pl-3"
style="font-size: x-large"
></b-form-textarea>
</b-input-group>
</validation-provider>
</div>
<br />
<b-row>
<b-col>
<b-button type="reset" variant="secondary" @click="onReset">
{{ $t('form.reset') }}
</b-button>
</b-col>
<b-col class="text-right">
<b-button type="submit" variant="success">
{{ $t('form.send_now') }}
</b-button>
</b-col>
</b-row>
<br />
</b-form>
</validation-observer>
</b-card>
</b-col>
</b-row>
<b-row v-show="row_check">
<b-col>
<div class="display-4 p-4">{{ $t('form.send_check') }}</div>
<b-list-group>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ ajaxCreateData.email }}
<b-badge variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ ajaxCreateData.amount }} GDD
<b-badge variant="primary" pill>{{ $t('form.amount') }}</b-badge>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ ajaxCreateData.memo ? ajaxCreateData.memo : '-' }}
<b-badge variant="primary" pill>{{ $t('form.message') }}</b-badge>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ $moment(ajaxCreateData.target_date).format('DD.MM.YYYY - HH:mm:ss') }}
<b-badge variant="primary" pill>{{ $t('form.date') }}</b-badge>
</b-list-group-item>
</b-list-group>
<hr />
<b-row>
<b-col>
<b-button @click="onReset">{{ $t('form.cancel') }}</b-button>
</b-col>
<b-col class="text-right">
<b-button variant="success" @click="sendTransaction">
{{ $t('form.send_now') }}
</b-button>
</b-col>
</b-row>
</b-col>
</b-row>
<b-row v-show="row_thx">
<b-col>
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
<div class="display-2 p-4">
{{ $t('form.thx') }}
<hr />
{{ $t('form.send_transaction_success') }}
</div>
<p class="text-center">
<b-button variant="success" @click="onReset">{{ $t('form.close') }}</b-button>
</p>
</b-card>
</b-col>
</b-row>
<b-row v-show="row_error">
<b-col>
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
<div class="display-2 p-4">
{{ $t('form.sorry') }}
<hr />
{{ $t('form.send_transaction_error') }}
</div>
<p class="text-center">
<b-button variant="success" @click="onReset">{{ $t('form.close') }}</b-button>
</p>
</b-card>
</b-col>
</b-row>
<slot :name="transactionSteps[currentTransactionStep]" />
</div>
</template>
<script>
// import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'
import { BIcon } from 'bootstrap-vue'
import communityAPI from '../../../apis/communityAPI.js'
export default {
name: 'GddSent',
components: {
// QrcodeStream,
// QrcodeDropZone,
BIcon,
},
props: {
balance: { type: Number, default: 0 },
showTransactionList: { type: Boolean, default: true },
},
name: 'GddSend',
data() {
return {
// scan: false,
show: true,
form: {
img: '',
email: '',
amount: '',
memo: '',
},
ajaxCreateData: {
email: '',
amount: 0,
target_date: '',
memo: '',
auto_sign: true,
},
send: false,
row_check: false,
row_thx: false,
row_error: false,
transactionSteps: ['transaction-form', 'transaction-confirmation', 'transaction-result'],
}
},
computed: {},
methods: {
// toggle() {
// this.scan = !this.scan
// },
// async onDecode(decodedString) {
// const arr = JSON.parse(decodedString)
// this.form.email = arr[0].email
// this.form.amount = arr[0].amount
// this.scan = false
// },
async onSubmit() {
// event.preventDefault()
this.ajaxCreateData.email = this.form.email
this.ajaxCreateData.amount = this.form.amount
const now = new Date(Date.now()).toISOString()
this.ajaxCreateData.target_date = now
this.ajaxCreateData.memo = this.form.memo
this.$emit('toggle-show-list', false)
this.row_check = true
this.row_thx = false
this.row_error = false
},
async sendTransaction() {
const result = await communityAPI.send(
this.$store.state.sessionId,
this.ajaxCreateData.email,
this.ajaxCreateData.amount,
this.ajaxCreateData.memo,
this.ajaxCreateData.target_date,
)
if (result.success) {
this.$emit('toggle-show-list', false)
this.row_check = false
this.row_thx = true
this.row_error = false
this.$emit('update-balance', { ammount: this.ajaxCreateData.amount })
} else {
this.$emit('toggle-show-list', true)
this.row_check = false
this.row_thx = false
this.row_error = true
}
},
onReset(event) {
event.preventDefault()
this.form.email = ''
this.form.amount = ''
this.form.memo = ''
this.show = false
this.$emit('toggle-show-list', true)
this.row_check = false
this.row_thx = false
this.row_error = false
this.$nextTick(() => {
this.show = true
})
},
props: {
currentTransactionStep: { type: Number, default: 0 },
},
}
</script>
<style>
.pointer {
cursor: pointer;
}
video {
max-height: 665px;
max-width: 665px;
}
span.errors {
color: red;
}
</style>

View File

@ -0,0 +1,65 @@
<template>
<b-alert show variant="secondary">
<span class="alert-text" v-html="$t('form.scann_code')"></span>
<b-col v-show="!scan" lg="12" class="text-right">
<a @click="toggle" class="nav-link pointer">
<img src="img/icons/gradido/qr-scan-pure.png" height="50" />
</a>
</b-col>
<div v-if="scan">
<b-row>
<qrcode-capture @detect="onDetect" capture="user"></qrcode-capture>
</b-row>
<qrcode-stream class="mt-3" @decode="onDecode" @detect="onDetect"></qrcode-stream>
<b-container>
<b-row>
<b-col lg="8">
<b-alert show variant="secondary">
<span class="alert-text" v-html="$t('form.scann_code')"></span>
</b-alert>
</b-col>
</b-row>
</b-container>
</div>
<div @click="toggle">
<b-alert v-show="scan" show variant="primary" class="pointer text-center">
<span class="alert-text">
<strong>{{ $t('form.cancel') }}</strong>
</span>
</b-alert>
</div>
</b-alert>
</template>
<script>
import { QrcodeStream } from 'vue-qrcode-reader'
export default {
name: 'QrCode',
components: {
QrcodeStream,
},
data() {
return {
scan: false,
}
},
methods: {
toggle() {
this.scan = !this.scan
},
async onDecode(decodedString) {
const arr = JSON.parse(decodedString)
this.$emit('set-transaction', { email: arr[0].email, amount: arr[0].amount })
this.scan = false
},
},
}
</script>
<style>
.pointer {
cursor: pointer;
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<b-row>
<b-col>
<div class="display-4 p-4">{{ $t('form.send_check') }}</div>
<b-list-group>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ email }}
<b-badge variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ amount }} GDD
<b-badge variant="primary" pill>{{ $t('form.amount') }}</b-badge>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ memo ? memo : '-' }}
<b-badge variant="primary" pill>{{ $t('form.message') }}</b-badge>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
{{ date }}
{{ $moment(date).format('DD.MM.YYYY - HH:mm:ss') }}
<b-badge variant="primary" pill>{{ $t('form.date') }}</b-badge>
</b-list-group-item>
</b-list-group>
<hr />
<b-row>
<b-col>
<b-button @click="$emit('on-reset')">{{ $t('form.cancel') }}</b-button>
</b-col>
<b-col class="text-right">
<b-button variant="success" :disabled="loading" @click="$emit('send-transaction')">
{{ $t('form.send_now') }}
</b-button>
</b-col>
</b-row>
</b-col>
</b-row>
</template>
<script>
export default {
name: 'TransactionConfirmation',
props: {
email: { type: String, default: '' },
amount: { type: String, default: '' },
memo: { type: String, default: '' },
date: { type: String, default: '' },
loading: { type: Boolean, default: false },
},
}
</script>

View File

@ -0,0 +1,121 @@
import { mount } from '@vue/test-utils'
import TransactionForm from './TransactionForm'
const localVue = global.localVue
describe('GddSend', () => {
let wrapper
const mocks = {
$t: jest.fn((t) => t),
$moment: jest.fn((m) => ({
format: () => m,
})),
$i18n: {
locale: jest.fn(() => 'en'),
},
$n: jest.fn((n) => String(n)),
$store: {
state: {
email: 'user@example.org',
},
},
}
const Wrapper = () => {
return mount(TransactionForm, { localVue, mocks })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders the component', () => {
expect(wrapper.find('div.transaction-form').exists()).toBeTruthy()
})
describe('warning messages', () => {
it('has a warning message', () => {
expect(wrapper.find('div.alert-default').find('span').text()).toBe('form.attention')
})
})
describe('transaction form', () => {
describe('email field', () => {
it('has an input field of type email', () => {
expect(wrapper.find('#input-group-1').find('input').attributes('type')).toBe('email')
})
it('has an envelope icon', () => {
expect(wrapper.find('#input-group-1').find('svg').attributes('aria-label')).toBe(
'envelope',
)
})
it('has a label form.receiver', () => {
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
})
it('has a placeholder "E-Mail"', () => {
expect(wrapper.find('#input-group-1').find('input').attributes('placeholder')).toBe(
'E-Mail',
)
})
})
describe('ammount field', () => {
it('has an input field of type number', () => {
expect(wrapper.find('#input-group-2').find('input').attributes('type')).toBe('number')
})
it('has an GDD text icon', () => {
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
})
it('has a label form.amount', () => {
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
})
it('has a placeholder "0.01"', () => {
expect(wrapper.find('#input-group-2').find('input').attributes('placeholder')).toBe(
'0.01',
)
})
})
describe('message text box', () => {
it('has an textarea field', () => {
expect(wrapper.find('#input-group-3').find('textarea').exists()).toBeTruthy()
})
it('has an chat-right-text icon', () => {
expect(wrapper.find('#input-group-3').find('svg').attributes('aria-label')).toBe(
'chat right text',
)
})
it('has a label form.memo', () => {
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
})
})
describe('cancel button', () => {
it('has a cancel button', () => {
expect(wrapper.find('button[type="reset"]').exists()).toBeTruthy()
})
it('has the text "form.cancel"', () => {
expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset')
})
it.skip('clears the email field on click', async () => {
wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv')
wrapper.find('button[type="reset"]').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.vm.form.email).toBeNull()
})
})
})
})
})

View File

@ -0,0 +1,175 @@
<template>
<b-row class="transaction-form">
<b-col xl="12" md="12">
<b-alert show dismissible variant="default" class="text-center">
<span class="alert-text h3 text-light" v-html="$t('form.attention')"></span>
</b-alert>
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
<!-- -<QrCode @set-transaction="setTransaction"></QrCode> -->
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
<b-form role="form" @submit.prevent="handleSubmit(onSubmit)" @reset="onReset">
<!-- <div>
<qrcode-drop-zone id="input-0" v-model="form.img"></qrcode-drop-zone>
</div>
<br />
-->
<div>
<validation-provider
name="Email"
:rules="{
required: true,
email: true,
is_not: $store.state.email,
}"
v-slot="{ errors }"
>
<b-row>
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
<b-col v-if="errors" class="text-right p-3 p-sm-1">
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
</b-col>
</b-row>
<b-input-group
id="input-group-1"
label="Empfänger:"
label-for="input-1"
description="We'll never share your email with anyone else."
size="lg"
class="mb-3"
>
<b-input-group-prepend class="p-3 d-none d-md-block">
<b-icon icon="envelope" class="display-3"></b-icon>
</b-input-group-prepend>
<b-form-input
id="input-1"
v-model="form.email"
type="email"
placeholder="E-Mail"
style="font-size: xx-large; padding-left: 20px"
></b-form-input>
</b-input-group>
</validation-provider>
</div>
<br />
<div>
<validation-provider
:name="$t('form.amount')"
:rules="{
required: true,
double: [2, $i18n.locale === 'de' ? ',' : '.'],
between: [0.01, balance],
}"
v-slot="{ errors }"
>
<b-row>
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
<b-col v-if="errors" class="text-right p-3 p-sm-1">
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
</b-col>
</b-row>
<b-input-group
id="input-group-2"
label="Betrag:"
label-for="input-2"
size="lg"
class="mb-3"
>
<b-input-group-prepend class="p-2 d-none d-md-block">
<div class="h3 pt-3 pr-3">GDD</div>
</b-input-group-prepend>
<b-form-input
id="input-2"
v-model="form.amount"
type="number"
:lang="$i18n.locale"
:placeholder="$n(0.01)"
step="0.01"
style="font-size: xx-large; padding-left: 20px"
></b-form-input>
</b-input-group>
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
<b-input-group id="input-group-3">
<b-input-group-prepend class="p-3 d-none d-md-block">
<b-icon icon="chat-right-text" class="display-3"></b-icon>
</b-input-group-prepend>
<b-form-textarea
rows="3"
v-model="form.memo"
class="pl-3"
style="font-size: x-large"
></b-form-textarea>
</b-input-group>
</validation-provider>
</div>
<br />
<b-row>
<b-col>
<b-button type="reset" variant="secondary" @click="onReset">
{{ $t('form.reset') }}
</b-button>
</b-col>
<b-col class="text-right">
<b-button type="submit" variant="success">
{{ $t('form.send_now') }}
</b-button>
</b-col>
</b-row>
<br />
</b-form>
</validation-observer>
</b-card>
</b-col>
</b-row>
</template>
<script>
// import QrCode from './QrCode'
// import { QrcodeDropZone } from 'vue-qrcode-reader'
import { BIcon } from 'bootstrap-vue'
export default {
name: 'TransactionForm',
components: {
BIcon,
// QrCode,
// QrcodeDropZone,
},
props: {
balance: { type: Number, default: 0 },
},
data() {
return {
form: {
email: '',
amount: '',
memo: '',
},
}
},
methods: {
onSubmit() {
this.$emit('set-transaction', {
email: this.form.email,
amount: this.form.amount,
memo: this.form.memo,
})
},
onReset(event) {
event.preventDefault()
this.form.email = ''
this.form.amount = ''
this.form.memo = ''
},
setTransaction(data) {
this.form.email = data.email
this.form.amount = data.amount
},
},
}
</script>
<style>
span.errors {
color: red;
}
</style>

View File

@ -0,0 +1,38 @@
<template>
<b-row v-if="!error">
<b-col>
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
<div class="display-2 p-4">
{{ $t('form.thx') }}
<hr />
{{ $t('form.send_transaction_success') }}
</div>
<p class="text-center">
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
</p>
</b-card>
</b-col>
</b-row>
<b-row v-else>
<b-col>
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
<div class="display-2 p-4">
{{ $t('form.sorry') }}
<hr />
{{ $t('form.send_transaction_error') }}
</div>
<p class="text-center">
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
</p>
</b-card>
</b-col>
</b-row>
</template>
<script>
export default {
name: 'TransactionResult',
props: {
error: { type: Boolean, default: true },
},
}
</script>

View File

@ -24,12 +24,30 @@ describe('GddStatus', () => {
wrapper = Wrapper()
})
it('it displays the ammount of GDD', () => {
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD')
describe('balance is loading', () => {
it('it displays em-dash as the ammount of GDD', () => {
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('— GDD')
})
it('it displays em-dash as the ammount of GDT', () => {
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('— GDT')
})
})
it('it displays the ammount of GDT', () => {
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT')
describe('balance is loaded', () => {
beforeEach(() => {
wrapper.setProps({
pending: false,
})
})
it('it displays the ammount of GDD', () => {
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD')
})
it('it displays the ammount of GDT', () => {
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT')
})
})
})
})

View File

@ -2,24 +2,14 @@
<div>
<b-row>
<b-col>
<stats-card
type="gradient-red"
sub-title="balance_gdd"
class="mb-4 h1"
style="background-color: #ebebeba3 !important"
>
{{ $n(balance) }} GDD
</stats-card>
<b-card style="background-color: #ebebeba3 !important">
{{ pending ? '—' : $n(balance) }} GDD
</b-card>
</b-col>
<b-col>
<stats-card
type="gradient-orange"
sub-title="balance_gdt"
class="mb-4 h1"
style="background-color: #ebebeba3 !important"
>
{{ $n(GdtBalance) }} GDT
</stats-card>
<b-card class="lg-h2 text-right" style="background-color: #ebebeba3 !important">
{{ pending ? '—' : $n(GdtBalance) }} GDT
</b-card>
</b-col>
</b-row>
</div>
@ -31,6 +21,10 @@ export default {
props: {
balance: { type: Number, default: 0 },
GdtBalance: { type: Number, default: 0 },
pending: {
type: Boolean,
default: true,
},
},
}
</script>

View File

@ -88,11 +88,9 @@
</b-card>
</b-collapse>
</b-list-group-item>
<b-list-group-item>
<b-alert v-if="transactions.length === 0" show variant="secondary">
<span class="alert-text">{{ $t('transaction.nullTransactions') }}</span>
</b-alert>
</b-list-group-item>
<div v-if="transactions.length === 0" class="mt-lg-4 text-center">
<span>{{ $t('transaction.nullTransactions') }}</span>
</div>
</b-list-group>
</div>
</template>
@ -102,7 +100,7 @@ export default {
name: 'GddTable',
props: {
transactions: { default: [] },
max: { type: Number, default: 25 },
max: { type: Number, default: 1000 },
timestamp: { type: Number, default: 0 },
transactionCount: { type: Number, default: 0 },
},

View File

@ -97,7 +97,6 @@
</p>
</div>
</transition>
<b-row class="my-4">
<b-col cols="12">
<base-input
@ -164,12 +163,7 @@ export default {
email: '',
agree: false,
},
rules: [
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
],
password: '',
checkPassword: '',
passwordVisible: false,
@ -231,6 +225,14 @@ export default {
emailFilled() {
return this.model.email !== ''
},
rules() {
return [
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
]
},
passwordValidation() {
const errors = []
for (const condition of this.rules) {

View File

@ -90,12 +90,6 @@ export default {
name: 'reset',
data() {
return {
rules: [
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
],
password: '',
checkPassword: '',
passwordVisible: false,
@ -137,6 +131,14 @@ export default {
passwordsFilled() {
return this.password !== '' && this.checkPassword !== ''
},
rules() {
return [
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
]
},
passwordValidation() {
const errors = []
for (const condition of this.rules) {

View File

@ -1,7 +1,7 @@
<template>
<div>
<div
class="header pb-8 pt-5 pt-lg-8 d-flex align-items-center profile-header"
class="header pb-8 pt-lg-4 d-flex align-items-center profile-header"
style="max-height: 200px"
></div>
<b-container fluid class="mt--6">

View File

@ -1,7 +1,7 @@
<template>
<div>
<!-- Header -->
<div class="header bg-gradient-info py-7 py-lg-8 pt-lg-9">
<div class="header py-7 py-lg-8 pt-lg-9">
<b-container>
<div class="header-body text-center mb-7">
<p class="h1">{{ $t('site.thx.title') }}</p>
@ -10,18 +10,6 @@
<b-button to="/login">{{ $t('login') }}</b-button>
</div>
</b-container>
<div class="separator separator-bottom separator-skew zindex-100">
<svg
x="0"
y="0"
viewBox="0 0 2560 100"
preserveAspectRatio="none"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<polygon class="fill-default" points="2560 0 2560 100 0 100"></polygon>
</svg>
</div>
</div>
<!-- Page content -->
</div>

View File

@ -134,6 +134,9 @@ int Gradido_LoginServer::main(const std::vector<std::string>& args)
#if defined(_WIN32) || defined(_WIN64)
log_Path = "./";
#endif
if (mConfigPath != "") {
log_Path = "./";
}
// init speed logger
Poco::AutoPtr<Poco::SimpleFileChannel> speedLogFileChannel(new Poco::SimpleFileChannel(log_Path + "speedLog.txt"));
@ -165,10 +168,14 @@ int Gradido_LoginServer::main(const std::vector<std::string>& args)
createConsoleFileAsyncLogger("emailLog", log_Path + "emailLog.txt");
// *************** load from config ********************************************
std::string cfg_Path = Poco::Path::config() + "grd_login/";
try {
loadConfiguration(cfg_Path + "grd_login.properties");
if(mConfigPath != "") {
loadConfiguration(mConfigPath);
} else {
loadConfiguration(cfg_Path + "grd_login.properties");
}
}
catch (Poco::Exception& ex) {
errorLog.error("error loading config: %s", ex.displayText());
@ -295,4 +302,4 @@ int Gradido_LoginServer::main(const std::vector<std::string>& args)
}
return Application::EXIT_OK;
}
}

View File

@ -382,6 +382,7 @@ int HandleElopageRequestTask::run()
DataTypeConverter::strToInt(mRequestData.get("noEmail", "0"), noEMail);
if (noEMail != 1) {
emailVerification->setBaseUrl(ServerConfig::g_serverPath + "/checkEmail");
em->addEmail(new model::Email(emailVerification, newUser, model::EMAIL_USER_VERIFICATION_CODE));
}
}

View File

@ -5,7 +5,7 @@
#include "Poco/DeflatingStream.h"
#line 6 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 6 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
#include "../SingletonManager/LanguageManager.h"
#include "../SingletonManager/SessionManager.h"
@ -20,7 +20,7 @@ enum PageState {
PAGE_WAIT_ADMIN,
PAGE_EMAIL_ALREADY_SEND
};
#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 1 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
#include "../ServerConfig.h"
@ -33,7 +33,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
if (_compressResponse) response.set("Content-Encoding", "gzip");
Poco::Net::HTMLForm form(request, request.stream());
#line 20 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 20 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
PageState state = PAGE_EMAIL_ASK;
auto lm = LanguageManager::getInstance();
@ -95,7 +95,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
// send reset password email
int result = 0;
if(user_exist) {
result = session->sendResetPasswordEmail(user, sendUserEmail, getBaseUrl());
result = session->sendResetPasswordEmail(user, sendUserEmail, ServerConfig::g_serverPath + "/checkEmail");
}
if(2 == result) {
@ -116,7 +116,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
}
#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 3 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
bool withMaterialIcons = false;
std::ostream& _responseStream = response.send();
@ -131,20 +131,20 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << "<meta charset=\"UTF-8\">\n";
responseStream << "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n";
responseStream << "<title>Gradido Login Server: ";
#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 11 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( pageName );
responseStream << "</title>\n";
responseStream << "<link rel=\"stylesheet\" type=\"text/css\" href=\"";
#line 12 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 12 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "css/main.css\">\n";
#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 13 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
if(withMaterialIcons) { responseStream << "\n";
responseStream << "<link rel=\"stylesheet\" type=\"text/css\" href=\"";
#line 14 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 14 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "css/materialdesignicons.min.css\">\n";
#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 15 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
} responseStream << "\n";
responseStream << "</head>\n";
responseStream << "<body>\n";
@ -152,20 +152,20 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << " <div class=\"center-form-single\">\n";
responseStream << " <div class=\"center-form-header\">\n";
responseStream << " <a href=\"";
#line 21 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 21 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "\" class=\"center-logo\">\n";
responseStream << " <picture>\n";
responseStream << " <source srcset=\"";
#line 23 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 23 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.webp\" type=\"image/webp\">\n";
responseStream << " <source srcset=\"";
#line 24 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 24 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.png\" type=\"image/png\">\n";
responseStream << " <img src=\"";
#line 25 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp"
#line 25 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\header.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.png\" alt=\"logo\" />\n";
responseStream << " </picture>\n";
@ -174,7 +174,7 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
// end include header.cpsp
responseStream << "\n";
responseStream << " ";
#line 103 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 103 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( getErrorsHtml() );
responseStream << "\n";
responseStream << "\t <div class=\"center-form-container\">\n";
@ -182,36 +182,36 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << "\t <h1>Passwort zurücksetzen</h1>\n";
responseStream << "\t </div>\n";
responseStream << " ";
#line 108 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 108 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
if(state == PAGE_EMAIL_ASK) { responseStream << "\n";
responseStream << " <div class=\"center-form-form\">\n";
responseStream << "\t\t\t\t<form action=\"";
#line 110 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 110 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( getBaseUrl() );
responseStream << "/resetPassword\">\n";
responseStream << "\t\t\t\t\t<div class=\"item-wrapper\">\n";
responseStream << "\t\t\t\t\t <div class=\"form-group\">\n";
responseStream << "\t\t\t\t\t\t<label class=\"form-label\" for=\"email\">";
#line 113 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 113 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Gib bitte hier deine E-Mail Adresse an:") );
responseStream << "</label>\n";
responseStream << "\t\t\t\t\t\t<input class=\"form-control\" type=\"text\" class=\"";
#line 114 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 114 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( emailInputClass );
responseStream << "\" name=\"email\" id=\"email\" placeholder=\"E-Mail\" value=\"";
#line 114 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 114 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( email );
responseStream << "\">\n";
responseStream << "\t\t\t\t\t </div>\n";
responseStream << "\t\t\t\t\t <button type=\"submit\" class=\"center-form-submit form-button\" >";
#line 116 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 116 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Bestätigen") );
responseStream << "</button>\n";
responseStream << "\t\t\t\t\t</div>\n";
responseStream << "\t\t\t\t</form>\n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t";
#line 120 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 120 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
} else if(state == PAGE_ASK) { responseStream << "\n";
responseStream << " <div class=\"center-form-form\">\n";
responseStream << "\t\t\t\t";
@ -219,22 +219,22 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << "<div class=\"center-form-selectors\">\n";
responseStream << "<form method=\"GET\" action=\"\">\n";
responseStream << "\t<button id=\"flag-england\" name=\"lang\" value=\"en\" title=\"English\" type=\"submit\" ";
#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\flags.cpsp"
#line 3 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\flags.cpsp"
if(lang != LANG_EN) { responseStream << "class=\"flag-btn\"";
#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\flags.cpsp"
#line 3 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\flags.cpsp"
}
else { responseStream << "class=\"flag-btn\" disabled";
#line 4 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\flags.cpsp"
#line 4 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\flags.cpsp"
} responseStream << ">\n";
responseStream << "\t <span class=\"flag flag-england\"></span>\n";
responseStream << "\t</button>\n";
responseStream << "\t<button id=\"flag-germany\" name=\"lang\" value=\"de\" title=\"Deutsch\" type=\"submit\" ";
#line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\flags.cpsp"
#line 7 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\flags.cpsp"
if(lang != LANG_DE) { responseStream << "class=\"flag-btn\"";
#line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\flags.cpsp"
#line 7 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\flags.cpsp"
}
else { responseStream << "class=\"flag-btn\" disabled";
#line 8 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\flags.cpsp"
#line 8 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\flags.cpsp"
} responseStream << ">\n";
responseStream << "\t <span class=\"flag flag-germany\"></span>\n";
responseStream << "\t</button>\n";
@ -243,33 +243,33 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
// end include flags.cpsp
responseStream << "\n";
responseStream << "\t\t\t\t<form action=\"";
#line 123 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 123 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( getBaseUrl() );
responseStream << "/resetPassword\">\n";
responseStream << "\t\t\t\t\t<label class=\"form-label\" for=\"email\">";
#line 124 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 124 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Gib bitte hier deine E-Mail Adresse an:") );
responseStream << "</label>\n";
responseStream << "\t\t\t\t\t<input class=\"form-control\" type=\"text\" class=\"";
#line 125 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 125 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( emailInputClass );
responseStream << "\" name=\"email\" id=\"email\" placeholder=\"E-Mail\" value=\"";
#line 125 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 125 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( email );
responseStream << "\">\n";
responseStream << "\t\t\t\t\t<label>";
#line 126 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 126 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Hast du dir deine Passphrase notiert oder gemerkt?") );
responseStream << "</label>\n";
responseStream << "\t\t\t\t\t<input class=\"form-control\" type=\"hidden\" name=\"ask_passphrase\" value=\"true\">\n";
responseStream << "\t\t\t\t\t<div class=\"";
#line 128 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 128 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( passphraseRadioClass );
responseStream << "\">\n";
responseStream << "\t\t\t\t\t\t<div class=\"radio\">\n";
responseStream << "\t\t\t\t\t\t <label class=\"form-label\" class=\"radio-label mr-4\">\n";
responseStream << "\t\t\t\t\t\t\t<input class=\"form-control\" name=\"passphrase_memorized\" onclick=\"removeGroupInvalidClass()\" type=\"radio\" value=\"true\">";
#line 131 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 131 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Ja") );
responseStream << " <i class=\"input-frame\"></i>\n";
responseStream << "\t\t\t\t\t\t </label>\n";
@ -277,53 +277,53 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << "\t\t\t\t\t\t<div class=\"radio\">\n";
responseStream << "\t\t\t\t\t\t <label class=\"form-label\" class=\"radio-label\">\n";
responseStream << "\t\t\t\t\t\t\t<input class=\"form-control\" name=\"passphrase_memorized\" onclick=\"removeGroupInvalidClass()\" type=\"radio\" value=\"false\">";
#line 136 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 136 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Nein") );
responseStream << " <i class=\"input-frame\"></i>\n";
responseStream << "\t\t\t\t\t\t </label>\n";
responseStream << "\t\t\t\t\t\t</div>\n";
responseStream << "\t\t\t\t\t</div>\n";
responseStream << "\t\t\t\t\t <button type=\"submit\" class=\"center-form-submit form-button\" name=\"ask\" >";
#line 140 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 140 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Absenden") );
responseStream << "</button>\n";
responseStream << "\t\t\t\t\t</div>\n";
responseStream << "\t\t\t\t</form>\n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t ";
#line 144 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 144 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
} else if(state == PAGE_WAIT_EMAIL) { responseStream << "\n";
responseStream << "\t\t\t";
#line 145 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 145 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Dir wird eine E-Mail zugeschickt um dein Passwort zur&uuml;ckzusetzen.") );
responseStream << "\n";
responseStream << "\t ";
#line 146 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 146 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
} else if(state == PAGE_WAIT_ADMIN) { responseStream << "\n";
responseStream << "\t\t\t";
#line 147 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 147 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Der Admin hat eine E-Mail bekommen und wird sich bei dir melden.") );
responseStream << "\n";
responseStream << "\t ";
#line 148 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 148 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
} else if(state == PAGE_EMAIL_ALREADY_SEND) { responseStream << "\n";
responseStream << "\t\t\t<p>";
#line 149 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 149 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Du hast bereits eine E-Mail bekommen. Bitte schau auch in dein Spam-Verzeichnis nach. ") );
responseStream << "</p>\n";
responseStream << "\t\t\t<p>";
#line 150 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 150 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("Du hast wirklich keine E-Mail erhalten und auch schon ein paar Minuten gewartet?") );
responseStream << "</p>\n";
responseStream << "\t\t\t<p><b><a href=\"mailto:";
#line 151 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 151 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( adminReceiver );
responseStream << "?subject=Error Reset Password email&amp;body=Hallo Dario,%0D%0A%0D%0Aich habe keine Passwort zurücksetzen E-Mail erhalten,%0D%0Akannst du das prüfen?%0D%0A%0D%0AMit freundlichen Grüßen%0D%0A\">";
#line 151 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 151 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
responseStream << ( langCatalog->gettext("E-Mail an Support schicken"));
responseStream << "</a></b></p>\n";
responseStream << "\t ";
#line 152 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\resetPassword.cpsp"
#line 152 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\resetPassword.cpsp"
} responseStream << "\n";
responseStream << " </div>\n";
responseStream << " </div>\n";
@ -345,14 +345,14 @@ void ResetPassword::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << " </div>\n";
responseStream << " <div class=\"bottomleft\">\n";
responseStream << " ";
#line 6 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\footer.cpsp"
#line 6 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\footer.cpsp"
responseStream << ( mTimeProfiler.string() );
responseStream << "\n";
responseStream << " </div>\n";
responseStream << " <div class=\"bottomright\">\n";
responseStream << " <p>Login Server in Entwicklung</p>\n";
responseStream << " <p>Alpha ";
#line 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\footer.cpsp"
#line 10 "F:\\Gradido\\gradido_local\\login_server\\src\\cpsp\\footer.cpsp"
responseStream << ( ServerConfig::g_versionString );
responseStream << "</p>\n";
responseStream << " </div>\n";

View File

@ -100,7 +100,9 @@ Poco::JSON::Object* JsonAdminEmailVerificationResend::handle(Poco::Dynamic::Var
if (emailVerification.isNull()) {
return stateError("no email verification code found");
}
emailVerification->getModel()->insertIntoDB(false);
emailVerification->setBaseUrl(ServerConfig::g_serverPath + "/checkEmail");
em->addEmail(new model::Email(emailVerification, receiverUser, model::EMAIL_ADMIN_USER_VERIFICATION_CODE_RESEND));
return stateSuccess();

View File

@ -109,7 +109,7 @@ Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params)
emailOptInModel->sendErrorsAsEmail();
return stateError("insert emailOptIn failed");
}
emailOptIn->setBaseUrl(mServerHost + "/" + ServerConfig::g_frontend_checkEmailPath);
emailOptIn->setBaseUrl(user->getGroupBaseUrl() + ServerConfig::g_frontend_checkEmailPath);
em->addEmail(new model::Email(emailOptIn, user, model::Email::convertTypeFromInt(emailType)));
if (login_after_register && session) {

View File

@ -69,8 +69,8 @@ namespace controller {
using namespace Poco::Data::Keywords;
Poco::Data::Statement select(session);
// typedef Poco::Tuple<std::string, std::string, std::string, Poco::Nullable<Poco::Data::BLOB>, int> UserTuple;
select << "SELECT id, first_name, last_name, email, pubkey, created, email_checked, disabled FROM " << db->getTableName();
// typedef Poco::Tuple<int, std::string, std::string, std::string, std::string, Poco::Nullable<Poco::Data::BLOB>, Poco::DateTime, int, int, int> UserTuple;
select << "SELECT id, first_name, last_name, email, username, pubkey, created, email_checked, disabled, group_id FROM " << db->getTableName();
select << " where email_checked = 0 ";
select, into(resultFromDB);
if (searchString != "") {

View File

@ -78,7 +78,7 @@ enum PageState {
// send reset password email
int result = 0;
if(user_exist) {
result = session->sendResetPasswordEmail(user, sendUserEmail, getBaseUrl());
result = session->sendResetPasswordEmail(user, sendUserEmail, ServerConfig::g_serverPath + "/checkEmail");
}
if(2 == result) {

View File

@ -3,12 +3,12 @@ COLOR_GREEN="\033[0;32m"
COLOR_YELLOW="\e[33m"
COLOR_NONE="\033[0m"
LOGIN_DB_USER=gradido_login
LOGIN_DB_NAME=gradido_login
LOGIN_DB_USER=gradido_login_live
LOGIN_DB_NAME=gradido_login_live
LOGIN_DB_PASSWD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo);
COMMUNITY_DB_USER=gradido_community
COMMUNITY_DB_NAME=gradido_community
COMMUNITY_DB_USER=gradido_community_live
COMMUNITY_DB_NAME=gradido_community_live
COMMUNITY_DB_PASSWD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo);
# create table

View File

@ -1,6 +1,6 @@
{
"name": "gradido",
"version": "0.9.4",
"version": "1.0.1",
"description": "Gradido",
"main": "index.js",
"repository": "git@github.com:gradido/gradido.git",