mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into community_decay_inside
This commit is contained in:
commit
119f344069
153
.github/workflows/test.yml
vendored
153
.github/workflows/test.yml
vendored
@ -44,19 +44,19 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
submodules: true
|
||||
##########################################################################
|
||||
# BUILD LOGIN SERVER DOCKER IMAGE ########################################
|
||||
##########################################################################
|
||||
- name: login server | Build `test` image
|
||||
- name: login server | Build `release` image
|
||||
run: |
|
||||
docker build --target login_server -t "gradido/login_server:test" -f ./login_server/Dockerfile login_server/
|
||||
docker save "gradido/login_server:test" > /tmp/login_server.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: docker-login-server-test
|
||||
path: /tmp/login_server.tar
|
||||
docker build --target release -t "gradido/login_server:release" -f ./login_server/Dockerfile login_server/
|
||||
#docker save "gradido/login_server:test" > /tmp/login_server.tar
|
||||
#- name: Upload Artifact
|
||||
# uses: actions/upload-artifact@v2
|
||||
#with:
|
||||
# name: docker-login-server-test
|
||||
#path: /tmp/login_server.tar
|
||||
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD TEST COMMUNITY SERVER ####################################
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
##########################################################################
|
||||
- name: mariadb | Build `test` image
|
||||
run: |
|
||||
docker build -t "gradido/mariadb:test" -f ./mariadb/Dockerfile ./
|
||||
docker build --target mariadb_server_test -t "gradido/mariadb:test" -f ./mariadb/Dockerfile ./
|
||||
docker save "gradido/mariadb:test" > /tmp/mariadb.tar
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
@ -212,9 +212,138 @@ jobs:
|
||||
report_name: Coverage Frontend
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
min_coverage: 20
|
||||
min_coverage: 28
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
# JOB: UNIT TEST LOGIN-SERVER ###############################################
|
||||
##############################################################################
|
||||
unit_test_login_server:
|
||||
name: Unit tests - Login-Server
|
||||
runs-on: ubuntu-latest
|
||||
needs: []
|
||||
services:
|
||||
mariadb:
|
||||
image: gradido/mariadb:test
|
||||
env:
|
||||
MARIADB_ALLOW_EMPTY_PASSWORD: 1
|
||||
MARIADB_USER: root
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping"
|
||||
--health-interval=6s
|
||||
--health-timeout=3s
|
||||
--health-retries=4
|
||||
steps:
|
||||
- name: Debug service
|
||||
run: echo "$(docker ps)"
|
||||
- name: Debug container choosing script
|
||||
run: echo "$(docker container ls | grep mariadb | awk '{ print $1 }')"
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
##########################################################################
|
||||
# Build Login-Server Test Docker image ###################################
|
||||
##########################################################################
|
||||
- name: login server | Build `test` image
|
||||
run: |
|
||||
docker build --target test -t "gradido/login_server:test" -f ./login_server/Dockerfile login_server/
|
||||
##########################################################################
|
||||
# UNIT TESTS BACKEND LOGIN-SERVER #######################################
|
||||
##########################################################################
|
||||
- name: Login-Server | Unit tests
|
||||
run: |
|
||||
docker run --network container:$(docker container ls | grep mariadb | awk '{ print $1 }') -v ~/coverage:/code/build_cov/coverage -v $(pwd)/configs/login_server:/etc/grd_login gradido/login_server:test
|
||||
cp -r ~/coverage ./coverage
|
||||
##########################################################################
|
||||
# COVERAGE CHECK BACKEND LOGIN-SERVER ####################################
|
||||
##########################################################################
|
||||
- name: backend login | Coverage check
|
||||
uses: webcraftmedia/coverage-check-action@master
|
||||
with:
|
||||
report_name: Coverage Backend Login
|
||||
type: lcov
|
||||
result_path: ./coverage/coverage.info
|
||||
min_coverage: 13
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
# JOB: UNIT TEST COMMUNITY-SERVER ###########################################
|
||||
##############################################################################
|
||||
unit_test_community_server:
|
||||
name: Unit tests - Community Server
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_test_community_server]
|
||||
services:
|
||||
mariadb:
|
||||
image: gradido/mariadb:test
|
||||
env:
|
||||
MARIADB_ALLOW_EMPTY_PASSWORD: 1
|
||||
MARIADB_USER: root
|
||||
# ports:
|
||||
# - 3306:3306
|
||||
options: --health-cmd="mysqladmin ping"
|
||||
--health-interval=5s
|
||||
--health-timeout=5s
|
||||
--health-retries=3
|
||||
steps:
|
||||
- name: get mariadb container id
|
||||
run: echo "::set-output name=id::$(docker container ls | grep mariadb | awk '{ print $1 }')"
|
||||
id: mariadb_container
|
||||
- name: show networks
|
||||
run: echo "$(docker network ls)"
|
||||
- name: get automatic created network
|
||||
run: echo "::set-output name=id::$(docker network ls | grep github_network | awk '{ print $1 }')"
|
||||
id: network
|
||||
- name: Start Login-Server
|
||||
run: docker run --network ${{ steps.network.outputs.id }} --name=login-server -d gradido/login_server:default
|
||||
- name: get login-server container id
|
||||
run: echo "::set-output name=id::$(docker container ls | grep login_server | awk '{ print $1 }')"
|
||||
id: login_server_container
|
||||
##########################################################################
|
||||
# CHECKOUT CODE ##########################################################
|
||||
##########################################################################
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
##########################################################################
|
||||
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||
##########################################################################
|
||||
- name: Download Docker Image (Community-Server)
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: docker-community-server-test
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/community_server.tar
|
||||
|
||||
# for debugging login-server
|
||||
- name: check login-server
|
||||
run: docker logs ${{ steps.login_server_container.outputs.id }}
|
||||
- name: check mariadb
|
||||
run: docker logs ${{ steps.mariadb_container.outputs.id }}
|
||||
##########################################################################
|
||||
# UNIT TESTS BACKEND COMMUNITY-SERVER #######################################
|
||||
##########################################################################
|
||||
- name: community server | Unit tests
|
||||
run: |
|
||||
docker run --network ${{ steps.network.outputs.id }} -v ~/coverage:/var/www/cakephp/webroot/coverage gradido/community_server:test
|
||||
cp -r ~/coverage ./coverage
|
||||
#########################################################################
|
||||
# COVERAGE CHECK BACKEND COMMUNITY-SERVER ####################################
|
||||
##########################################################################
|
||||
- name: backend community | Coverage check
|
||||
uses: einhornimmond/coverage-check-action@master
|
||||
with:
|
||||
report_name: Coverage Backend Community
|
||||
type: phpunit
|
||||
result_path: ./coverage/coverage.info
|
||||
min_coverage: 10
|
||||
token: ${{ github.token }}
|
||||
|
||||
#test:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
@ -228,4 +357,4 @@ jobs:
|
||||
# GN_INSTANCE_FOLDER: /tmp/gradio-node-instance
|
||||
# GN_CONTAINER_NAME: gradido-node-build
|
||||
# run: docker run gradido-node-test
|
||||
# timeout-minutes: 2
|
||||
# timeout-minutes: 2
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
FROM phpdockerio/php74-fpm
|
||||
FROM phpdockerio/php74-fpm as community_server
|
||||
|
||||
# install php fpm
|
||||
RUN apt-get update \
|
||||
&& apt-get -y --no-install-recommends install curl unzip php7.4-curl php7.4-fpm php7.4-mbstring php7.4-intl php7.4-xml php7.4-pdo php7.4-mysql \
|
||||
&& apt-get -y --no-install-recommends install curl unzip php7.4-curl php7.4-fpm php7.4-mbstring php7.4-intl php7.4-xml php7.4-pdo php7.4-mysql php7.4-xdebug \
|
||||
&& apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
||||
|
||||
WORKDIR /var/www/cakephp
|
||||
@ -13,5 +13,18 @@ COPY ./configs/community_server/app.php ./config/
|
||||
RUN composer update
|
||||
RUN composer dump-autoload
|
||||
|
||||
######### special for code coverage and testing
|
||||
FROM community_server as test
|
||||
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get -y --no-install-recommends install php7.4-xdebug \
|
||||
&& apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
||||
|
||||
|
||||
ENV XDEBUG_MODE=coverage
|
||||
#RUN composer require --dev rregeer/phpunit-coverage-check
|
||||
|
||||
#CMD ./vendor/bin/phpunit --coverage-clover=./webroot/coverage/clover.xml
|
||||
CMD ./vendor/bin/phpunit --coverage-text=./webroot/coverage/coverage.info
|
||||
|
||||
|
||||
@ -60,19 +60,21 @@ Router::scope('/', function (RouteBuilder $routes) {
|
||||
$whitelist = ['JsonRequestHandler', 'ElopageWebhook', 'AppRequests'];
|
||||
$ajaxWhitelist = ['TransactionSendCoins', 'TransactionCreations'];
|
||||
|
||||
$callerIp = $request->clientIp();
|
||||
|
||||
foreach($whitelist as $entry) {
|
||||
if($request->getParam('controller') === $entry) {
|
||||
if($entry == 'ElopageWebhook' || $entry == 'AppRequests') {
|
||||
return true;
|
||||
}
|
||||
$allowedIpLocalhost = ['127.0.0.1', 'localhost', '', '::1'];
|
||||
if(in_array($clientIp, $allowedIpLocalhost)) {
|
||||
if(in_array($callerIp, $allowedIpLocalhost)) {
|
||||
return true;
|
||||
}
|
||||
$allowedCaller = Configure::read('API.allowedCaller');
|
||||
$ipPerHost = [];
|
||||
if($allowedCaller && count($allowedCaller) > 0) {
|
||||
$callerIp = $request->clientIp();
|
||||
|
||||
foreach($allowedCaller as $allowed) {
|
||||
$ip = gethostbyname($allowed);
|
||||
$ipPerHost[$allowed] = $ip;
|
||||
|
||||
@ -88,19 +88,8 @@ class AppController extends Controller
|
||||
// load current balance
|
||||
$session = $this->getRequest()->getSession();
|
||||
$state_user_id = $session->read('StateUser.id');
|
||||
if ($state_user_id) {
|
||||
$stateBalancesTable = TableRegistry::getTableLocator()->get('stateBalances');
|
||||
$stateBalanceQuery = $stateBalancesTable
|
||||
->find('all')
|
||||
->contain(false)
|
||||
->where(['state_user_id' => $state_user_id]);
|
||||
if ($stateBalanceQuery->count() == 1) {
|
||||
//var_dump($stateBalanceEntry->first());
|
||||
$session->write('StateUser.balance', $stateBalanceQuery->first()->decay);
|
||||
//echo "stateUser.balance: " . $session->read('StateUser.balance');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// load error count
|
||||
if ($state_user_id) {
|
||||
$stateErrorsTable = TableRegistry::getTableLocator()->get('stateErrors');
|
||||
@ -111,8 +100,6 @@ class AppController extends Controller
|
||||
->where(['state_user_id' => $state_user_id]);
|
||||
$session->write('StateUser.errorCount', $stateErrorQuery->count());
|
||||
}
|
||||
//echo "initialize";
|
||||
|
||||
|
||||
// put current page into global for navi
|
||||
$GLOBALS["passed"] = null;
|
||||
|
||||
@ -152,10 +152,7 @@ class AppRequestsController extends AppController
|
||||
if($result !== true) {
|
||||
return $this->returnJson($result);
|
||||
}
|
||||
$required_fields = $this->checkAndCopyRequiredFields(['target_date'], $params, $data);
|
||||
if($required_fields !== true) {
|
||||
return $this->returnJson($required_fields);
|
||||
}
|
||||
|
||||
if(!isset($params['memo']) || strlen($params['memo']) < 5 || strlen($params['memo']) > 150) {
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'memo is not set or not in expected range [5;150]']);
|
||||
}
|
||||
@ -276,7 +273,8 @@ class AppRequestsController extends AppController
|
||||
$this->viewBuilder()->setLayout('ajax');
|
||||
$login_result = $this->requestLogin($session_id, false);
|
||||
if($login_result !== true) {
|
||||
return $this->returnJson($login_result);
|
||||
$this->set('body', $login_result);
|
||||
return;
|
||||
}
|
||||
$session = $this->getRequest()->getSession();
|
||||
$user = $session->read('StateUser');
|
||||
@ -285,16 +283,24 @@ class AppRequestsController extends AppController
|
||||
|
||||
$state_balance = $state_balances_table->find()->where(['state_user_id' => $user['id']])->first();
|
||||
|
||||
if(!$state_balance) {
|
||||
return $this->returnJson(['state' => 'success', 'balance' => 0]);
|
||||
}
|
||||
|
||||
$now = new FrozenTime();
|
||||
$body = [
|
||||
'state' => 'success',
|
||||
'balance' => $state_balance->amount,
|
||||
'decay' => $state_balance->partDecay($now),
|
||||
'decay_date' => $now
|
||||
];
|
||||
if(!$state_balance) {
|
||||
$body = [
|
||||
'state' => 'success',
|
||||
'balance' => 0,
|
||||
'decay' => 0
|
||||
];
|
||||
} else {
|
||||
|
||||
$body = [
|
||||
'state' => 'success',
|
||||
'balance' => $state_balance->amount,
|
||||
'decay' => $state_balance->partDecay($now),
|
||||
];
|
||||
}
|
||||
|
||||
$body['decay_date'] = $now;
|
||||
$this->set('body', $body);
|
||||
}
|
||||
|
||||
@ -302,35 +308,31 @@ class AppRequestsController extends AppController
|
||||
{
|
||||
$this->viewBuilder()->setLayout('ajax');
|
||||
$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');
|
||||
|
||||
|
||||
|
||||
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||
|
||||
|
||||
$stateBalancesTable->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 {
|
||||
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id'] ? $user['id'] : 0);
|
||||
}
|
||||
|
||||
$stateUserTransactions_total = $stateUserTransactionsTable
|
||||
->find()
|
||||
->select(['id'])
|
||||
->where(['state_user_id' => $user['id']])
|
||||
->contain([]);
|
||||
|
||||
$stateUserTransactionsQuery = $stateUserTransactionsTable
|
||||
->find()
|
||||
@ -343,17 +345,18 @@ class AppRequestsController extends AppController
|
||||
$decay = true;
|
||||
$transactions = [];
|
||||
$transactions_from_db = $stateUserTransactionsQuery->toArray();
|
||||
if($stateUserTransactionsQuery->count() > 0) {
|
||||
|
||||
if(count($transactions_from_db)) {
|
||||
if($orderDirection == 'DESC') {
|
||||
$transactions_from_db = array_reverse($transactions_from_db);
|
||||
}
|
||||
|
||||
$transactions = $transactionsTable->listTransactionsHumanReadable($transactions_from_db, $user, $decay);
|
||||
|
||||
if($orderDirection == 'DESC') {
|
||||
$transactions = array_reverse($transactions);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $user['id']])->first();
|
||||
|
||||
@ -361,7 +364,7 @@ class AppRequestsController extends AppController
|
||||
'state' => 'success',
|
||||
'transactions' => $transactions,
|
||||
'transactionExecutingCount' => $session->read('Transactions.executing'),
|
||||
'count' => $stateUserTransactions_total->count(),
|
||||
'count' => $stateUserTransactionsQuery->count(),
|
||||
'gdtSum' => $gdtSum,
|
||||
'timeUsed' => microtime(true) - $startTime
|
||||
];
|
||||
@ -375,8 +378,8 @@ class AppRequestsController extends AppController
|
||||
$body['balance'] = $state_balance->amount;
|
||||
$body['decay'] = $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now);
|
||||
}
|
||||
|
||||
$this->set('body', $body);
|
||||
|
||||
$this->set('body', $body);
|
||||
}
|
||||
|
||||
private function acquireAccessToken($session_id)
|
||||
|
||||
@ -340,12 +340,13 @@ class JsonRequestHandlerController extends AppController {
|
||||
return;
|
||||
}
|
||||
$transaction_body = $transaction->getTransactionBody();
|
||||
$transaction_type_name = $transaction_body->getTransactionTypeName();
|
||||
$senderUser = null;
|
||||
if($transaction_type_name === 'transfer') {
|
||||
$senderUser = $transaction_body->getSpecificTransaction()->getSenderUser();
|
||||
} else if($transaction_type_name === 'creation') {
|
||||
$senderUser = $transaction->getFirstSigningUser();
|
||||
$senderUser = $transaction->getFirstSigningUser();
|
||||
if($transaction_body != null) {
|
||||
$transaction_type_name = $transaction_body->getTransactionTypeName();
|
||||
|
||||
if($transaction_type_name === 'transfer') {
|
||||
$senderUser = $transaction_body->getSpecificTransaction()->getSenderUser();
|
||||
}
|
||||
}
|
||||
// send notification email
|
||||
$noReplyEmail = Configure::read('noReplyEmail');
|
||||
@ -373,22 +374,29 @@ class JsonRequestHandlerController extends AppController {
|
||||
|
||||
private function putTransaction($transactionBase64) {
|
||||
$transaction = new Transaction($transactionBase64);
|
||||
//echo "after new transaction<br>";
|
||||
|
||||
if($transaction->hasErrors()) {
|
||||
$this->sendEMailTransactionFailed($transaction, 'parse');
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'error parsing transaction', 'details' => $transaction->getErrors()]);
|
||||
}
|
||||
//echo "after check on errors<br>";
|
||||
|
||||
if(!$transaction->validate()) {
|
||||
//$transaction_details
|
||||
$this->sendEMailTransactionFailed($transaction, 'validate');
|
||||
return $this->returnJsonSaveError($transaction, ['state' => 'error', 'msg' => 'error validate transaction', 'details' => $transaction->getErrors()]);
|
||||
return $this->returnJsonSaveError($transaction, [
|
||||
'state' => 'error',
|
||||
'msg' => 'error validate transaction',
|
||||
'details' => $transaction->getErrors()
|
||||
]);
|
||||
}
|
||||
//echo "after validate <br>";
|
||||
|
||||
if ($transaction->save()) {
|
||||
$result = ['state' => 'success'];
|
||||
if($transaction->hasWarnings()) {
|
||||
$result['warnings'] = $transaction->getWarnings();
|
||||
}
|
||||
// success
|
||||
return $this->returnJson(['state' => 'success']);
|
||||
return $this->returnJson($result);
|
||||
} else {
|
||||
|
||||
$this->sendEMailTransactionFailed($transaction, 'save');
|
||||
|
||||
@ -151,35 +151,6 @@ class StateBalancesController extends AppController
|
||||
$this->set('gdtSum', $gdtSum);
|
||||
}
|
||||
|
||||
public function ajaxGetBalance($session_id = 0)
|
||||
{
|
||||
if(!$session_id) {
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']);
|
||||
}
|
||||
$login_result = $this->requestLogin($session_id, false);
|
||||
if($login_result !== true) {
|
||||
return $this->returnJson($login_result);
|
||||
}
|
||||
$session = $this->getRequest()->getSession();
|
||||
$user = $session->read('StateUser');
|
||||
|
||||
$this->StateBalances->updateBalances($user['id']);
|
||||
|
||||
$state_balance = $this->StateBalances->find()->where(['state_user_id' => $user['id']])->first();
|
||||
|
||||
if(!$state_balance) {
|
||||
return $this->returnJson(['state' => 'success', 'balance' => 0]);
|
||||
}
|
||||
$now = new FrozenTime();
|
||||
|
||||
return $this->returnJson([
|
||||
'state' => 'success',
|
||||
'balance' => $state_balance->amount,
|
||||
'decay' => $this->StateBalances->calculateDecay($state_balance->amount, $state_balance->record_date, $now),
|
||||
'decay_date' => $now
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function ajaxGdtOverview()
|
||||
{
|
||||
|
||||
@ -7,6 +7,7 @@ use Model\Transactions\Transaction;
|
||||
use Model\Transactions\TransactionBody;
|
||||
|
||||
use Cake\Core\Configure;
|
||||
use Cake\I18n\Time;
|
||||
use Cake\ORM\TableRegistry;
|
||||
|
||||
/**
|
||||
@ -24,7 +25,7 @@ class TransactionsController extends AppController
|
||||
parent::initialize();
|
||||
$this->loadComponent('GradidoNumber');
|
||||
$this->loadComponent('JsonRpcRequestClient');
|
||||
$this->Auth->allow(['decode']);
|
||||
$this->Auth->allow(['decode', 'manualTransaction']);
|
||||
|
||||
}
|
||||
/**
|
||||
@ -170,6 +171,78 @@ class TransactionsController extends AppController
|
||||
$this->set('transaction', $transaction);
|
||||
}
|
||||
|
||||
public function manualTransaction()
|
||||
{
|
||||
if ($this->request->is('post')) {
|
||||
$data = $this->request->getData();
|
||||
$type = $data['type'];
|
||||
|
||||
$transaction = new \Proto\Gradido\GradidoTransaction();
|
||||
$transactionBody = new \Proto\Gradido\TransactionBody();
|
||||
$transactionBody->setMemo($data['memo']);
|
||||
$created = new \Proto\Gradido\TimestampSeconds();
|
||||
$now = new Time();
|
||||
$created->setSeconds($now->getTimestamp());
|
||||
$transactionBody->setCreated($created);
|
||||
if($type == "creation") {
|
||||
$creation = new \Proto\Gradido\GradidoCreation();
|
||||
$target_date = new \Proto\Gradido\TimestampSeconds();
|
||||
$target_time = new Time($data['target_date']);
|
||||
$target_date->setSeconds($target_time->getTimestamp());
|
||||
$creation->setTargetDate($target_date);
|
||||
$receiver = new \Proto\Gradido\TransferAmount();
|
||||
$receiver->setAmount(intval($data['amount']));
|
||||
$receiver->setPubkey(hex2bin($data['target_public_key']));
|
||||
$creation->setReceiver($receiver);
|
||||
$transactionBody->setCreation($creation);
|
||||
} else if($type == "transfer") {
|
||||
$transfer = new \Proto\Gradido\GradidoTransfer();
|
||||
$local_transfer = new \Proto\Gradido\LocalTransfer();
|
||||
$sender = new \Proto\Gradido\TransferAmount();
|
||||
$sender->setAmount(intval($data['amount']));
|
||||
$sender->setPubkey(hex2bin($data['sender_public_key']));
|
||||
$local_transfer->setSender($sender);
|
||||
$local_transfer->setReceiver(hex2bin($data['receiver_public_key']));
|
||||
$transfer->setLocal($local_transfer);
|
||||
$transactionBody->setTransfer($transfer);
|
||||
}
|
||||
$body_bytes = $transactionBody->serializeToString();
|
||||
$transaction->setBodyBytes($body_bytes);
|
||||
|
||||
$protoSigMap = new \Proto\Gradido\SignatureMap();
|
||||
$sigPairs = $protoSigMap->getSigPair();
|
||||
//echo "sigPairs: "; var_dump($sigPairs); echo "<br>";
|
||||
//return null;
|
||||
|
||||
// sign with keys
|
||||
//foreach($keys as $key) {
|
||||
$sigPair = new \Proto\Gradido\SignaturePair();
|
||||
$sigPair->setPubKey(hex2bin($data['signer_public_key']));
|
||||
|
||||
$signature = sodium_crypto_sign_detached($body_bytes, hex2bin($data['signer_private_key']));
|
||||
echo "signature: " . bin2hex($signature). "<br>";
|
||||
$sigPair->setEd25519($signature);
|
||||
|
||||
$sigPairs[] = $sigPair;
|
||||
// SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
|
||||
// SODIUM_BASE64_VARIANT_ORIGINAL
|
||||
$transaction->setSigMap($protoSigMap);
|
||||
//var_dump($protoSigMap);
|
||||
$transaction_bin = $transaction->serializeToString();
|
||||
// $url_safe = sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_ORIGINAL);
|
||||
$base64 = [
|
||||
//'original' => sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_ORIGINAL),
|
||||
//'original_nopadding' => sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_ORIGINAL_NO_PADDING),
|
||||
//'urlsafe' => sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_URLSAFE),
|
||||
'urlsafe_nopadding' => sodium_bin2base64($transaction_bin, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING),
|
||||
'php' => base64_encode($transaction_bin)
|
||||
|
||||
];
|
||||
|
||||
$this->set('base64', $base64);
|
||||
}
|
||||
}
|
||||
|
||||
public function decode()
|
||||
{
|
||||
$this->viewBuilder()->setLayout('frontend');
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.Key</code>
|
||||
*/
|
||||
class Key extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $ed25519
|
||||
* ed25519 signature (libsodium default)
|
||||
* @type string $ed25519_ref10
|
||||
* ed25519 ref10 signature
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 signature (libsodium default)
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getEd25519()
|
||||
{
|
||||
return $this->readOneof(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 signature (libsodium default)
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setEd25519($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->writeOneof(2, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 ref10 signature
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getEd25519Ref10()
|
||||
{
|
||||
return $this->readOneof(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 ref10 signature
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setEd25519Ref10($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->writeOneof(3, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return $this->whichOneof("key");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.ReceiverAmount</code>
|
||||
*/
|
||||
class ReceiverAmount extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes ed25519_receiver_pubkey = 1;</code>
|
||||
*/
|
||||
private $ed25519_receiver_pubkey = '';
|
||||
/**
|
||||
* Generated from protobuf field <code>sint64 amount = 2;</code>
|
||||
*/
|
||||
private $amount = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $ed25519_receiver_pubkey
|
||||
* @type int|string $amount
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes ed25519_receiver_pubkey = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getEd25519ReceiverPubkey()
|
||||
{
|
||||
return $this->ed25519_receiver_pubkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes ed25519_receiver_pubkey = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setEd25519ReceiverPubkey($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->ed25519_receiver_pubkey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>sint64 amount = 2;</code>
|
||||
* @return int|string
|
||||
*/
|
||||
public function getAmount()
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>sint64 amount = 2;</code>
|
||||
* @param int|string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setAmount($var)
|
||||
{
|
||||
GPBUtil::checkInt64($var);
|
||||
$this->amount = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,119 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.SenderAmount</code>
|
||||
*/
|
||||
class SenderAmount extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes ed25519_sender_pubkey = 1;</code>
|
||||
*/
|
||||
private $ed25519_sender_pubkey = '';
|
||||
/**
|
||||
* Generated from protobuf field <code>sint64 amount = 2;</code>
|
||||
*/
|
||||
private $amount = 0;
|
||||
/**
|
||||
* sender balance after transaction, including perishability
|
||||
*
|
||||
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
|
||||
*/
|
||||
private $senderFinalBalance = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $ed25519_sender_pubkey
|
||||
* @type int|string $amount
|
||||
* @type int|string $senderFinalBalance
|
||||
* sender balance after transaction, including perishability
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes ed25519_sender_pubkey = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getEd25519SenderPubkey()
|
||||
{
|
||||
return $this->ed25519_sender_pubkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes ed25519_sender_pubkey = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setEd25519SenderPubkey($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->ed25519_sender_pubkey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>sint64 amount = 2;</code>
|
||||
* @return int|string
|
||||
*/
|
||||
public function getAmount()
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>sint64 amount = 2;</code>
|
||||
* @param int|string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setAmount($var)
|
||||
{
|
||||
GPBUtil::checkInt64($var);
|
||||
$this->amount = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* sender balance after transaction, including perishability
|
||||
*
|
||||
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
|
||||
* @return int|string
|
||||
*/
|
||||
public function getSenderFinalBalance()
|
||||
{
|
||||
return $this->senderFinalBalance;
|
||||
}
|
||||
|
||||
/**
|
||||
* sender balance after transaction, including perishability
|
||||
*
|
||||
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
|
||||
* @param int|string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setSenderFinalBalance($var)
|
||||
{
|
||||
GPBUtil::checkInt64($var);
|
||||
$this->senderFinalBalance = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.SignatureMap</code>
|
||||
*/
|
||||
class SignatureMap extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Each signature pair corresponds to a unique Key required to sign the transaction.
|
||||
*
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
|
||||
*/
|
||||
private $sigPair;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type \Model\Messages\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $sigPair
|
||||
* Each signature pair corresponds to a unique Key required to sign the transaction.
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each signature pair corresponds to a unique Key required to sign the transaction.
|
||||
*
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
|
||||
* @return \Google\Protobuf\Internal\RepeatedField
|
||||
*/
|
||||
public function getSigPair()
|
||||
{
|
||||
return $this->sigPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each signature pair corresponds to a unique Key required to sign the transaction.
|
||||
*
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
|
||||
* @param \Model\Messages\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setSigPair($var)
|
||||
{
|
||||
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Model\Messages\Gradido\SignaturePair::class);
|
||||
$this->sigPair = $arr;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,123 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.SignaturePair</code>
|
||||
*/
|
||||
class SignaturePair extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes pubKey = 1;</code>
|
||||
*/
|
||||
private $pubKey = '';
|
||||
protected $signature;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $pubKey
|
||||
* @type string $ed25519
|
||||
* ed25519 signature (libsodium default)
|
||||
* @type string $ed25519_ref10
|
||||
* ed25519 ref10 signature
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes pubKey = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getPubKey()
|
||||
{
|
||||
return $this->pubKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes pubKey = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setPubKey($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->pubKey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 signature (libsodium default)
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getEd25519()
|
||||
{
|
||||
return $this->readOneof(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 signature (libsodium default)
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setEd25519($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->writeOneof(2, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 ref10 signature
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getEd25519Ref10()
|
||||
{
|
||||
return $this->readOneof(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* ed25519 ref10 signature
|
||||
*
|
||||
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setEd25519Ref10($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->writeOneof(3, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSignature()
|
||||
{
|
||||
return $this->whichOneof("signature");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,114 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: StateCreateGroup.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* need signature from this group and from parent (if it isn't zero)
|
||||
*
|
||||
* Generated from protobuf message <code>model.messages.gradido.StateCreateGroup</code>
|
||||
*/
|
||||
class StateCreateGroup extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
*/
|
||||
private $name = '';
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 2;</code>
|
||||
*/
|
||||
private $groupPublicKey = null;
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key parentGroupPublicKey = 3;</code>
|
||||
*/
|
||||
private $parentGroupPublicKey = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $name
|
||||
* @type \Model\Messages\Gradido\Key $groupPublicKey
|
||||
* @type \Model\Messages\Gradido\Key $parentGroupPublicKey
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\StateCreateGroup::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->name = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 2;</code>
|
||||
* @return \Model\Messages\Gradido\Key
|
||||
*/
|
||||
public function getGroupPublicKey()
|
||||
{
|
||||
return $this->groupPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 2;</code>
|
||||
* @param \Model\Messages\Gradido\Key $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupPublicKey($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
|
||||
$this->groupPublicKey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key parentGroupPublicKey = 3;</code>
|
||||
* @return \Model\Messages\Gradido\Key
|
||||
*/
|
||||
public function getParentGroupPublicKey()
|
||||
{
|
||||
return $this->parentGroupPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key parentGroupPublicKey = 3;</code>
|
||||
* @param \Model\Messages\Gradido\Key $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentGroupPublicKey($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
|
||||
$this->parentGroupPublicKey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,114 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: StateGroupChangeParent.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* need signature from this group and from both parents (if it isn't zero)
|
||||
*
|
||||
* Generated from protobuf message <code>model.messages.gradido.StateGroupChangeParent</code>
|
||||
*/
|
||||
class StateGroupChangeParent extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 1;</code>
|
||||
*/
|
||||
private $groupPublicKey = null;
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key newParentGroupPublicKey = 2;</code>
|
||||
*/
|
||||
private $newParentGroupPublicKey = null;
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key oldParentGroupPublicKey = 3;</code>
|
||||
*/
|
||||
private $oldParentGroupPublicKey = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type \Model\Messages\Gradido\Key $groupPublicKey
|
||||
* @type \Model\Messages\Gradido\Key $newParentGroupPublicKey
|
||||
* @type \Model\Messages\Gradido\Key $oldParentGroupPublicKey
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\StateGroupChangeParent::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 1;</code>
|
||||
* @return \Model\Messages\Gradido\Key
|
||||
*/
|
||||
public function getGroupPublicKey()
|
||||
{
|
||||
return $this->groupPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 1;</code>
|
||||
* @param \Model\Messages\Gradido\Key $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupPublicKey($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
|
||||
$this->groupPublicKey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key newParentGroupPublicKey = 2;</code>
|
||||
* @return \Model\Messages\Gradido\Key
|
||||
*/
|
||||
public function getNewParentGroupPublicKey()
|
||||
{
|
||||
return $this->newParentGroupPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key newParentGroupPublicKey = 2;</code>
|
||||
* @param \Model\Messages\Gradido\Key $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setNewParentGroupPublicKey($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
|
||||
$this->newParentGroupPublicKey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key oldParentGroupPublicKey = 3;</code>
|
||||
* @return \Model\Messages\Gradido\Key
|
||||
*/
|
||||
public function getOldParentGroupPublicKey()
|
||||
{
|
||||
return $this->oldParentGroupPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Key oldParentGroupPublicKey = 3;</code>
|
||||
* @param \Model\Messages\Gradido\Key $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setOldParentGroupPublicKey($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
|
||||
$this->oldParentGroupPublicKey = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* An exact date and time. This is the same data structure as the protobuf Timestamp.proto (see the comments in https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto)
|
||||
*
|
||||
* Generated from protobuf message <code>model.messages.gradido.Timestamp</code>
|
||||
*/
|
||||
class Timestamp extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Number of complete seconds since the start of the epoch
|
||||
*
|
||||
* Generated from protobuf field <code>int64 seconds = 1;</code>
|
||||
*/
|
||||
private $seconds = 0;
|
||||
/**
|
||||
* Number of nanoseconds since the start of the last second
|
||||
*
|
||||
* Generated from protobuf field <code>int32 nanos = 2;</code>
|
||||
*/
|
||||
private $nanos = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type int|string $seconds
|
||||
* Number of complete seconds since the start of the epoch
|
||||
* @type int $nanos
|
||||
* Number of nanoseconds since the start of the last second
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of complete seconds since the start of the epoch
|
||||
*
|
||||
* Generated from protobuf field <code>int64 seconds = 1;</code>
|
||||
* @return int|string
|
||||
*/
|
||||
public function getSeconds()
|
||||
{
|
||||
return $this->seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of complete seconds since the start of the epoch
|
||||
*
|
||||
* Generated from protobuf field <code>int64 seconds = 1;</code>
|
||||
* @param int|string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setSeconds($var)
|
||||
{
|
||||
GPBUtil::checkInt64($var);
|
||||
$this->seconds = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of nanoseconds since the start of the last second
|
||||
*
|
||||
* Generated from protobuf field <code>int32 nanos = 2;</code>
|
||||
* @return int
|
||||
*/
|
||||
public function getNanos()
|
||||
{
|
||||
return $this->nanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of nanoseconds since the start of the last second
|
||||
*
|
||||
* Generated from protobuf field <code>int32 nanos = 2;</code>
|
||||
* @param int $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setNanos($var)
|
||||
{
|
||||
GPBUtil::checkInt32($var);
|
||||
$this->nanos = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: BasicTypes.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* An exact date and time, with a resolution of one second (no nanoseconds).
|
||||
*
|
||||
* Generated from protobuf message <code>model.messages.gradido.TimestampSeconds</code>
|
||||
*/
|
||||
class TimestampSeconds extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Number of complete seconds since the start of the epoch
|
||||
*
|
||||
* Generated from protobuf field <code>int64 seconds = 1;</code>
|
||||
*/
|
||||
private $seconds = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type int|string $seconds
|
||||
* Number of complete seconds since the start of the epoch
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\BasicTypes::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of complete seconds since the start of the epoch
|
||||
*
|
||||
* Generated from protobuf field <code>int64 seconds = 1;</code>
|
||||
* @return int|string
|
||||
*/
|
||||
public function getSeconds()
|
||||
{
|
||||
return $this->seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of complete seconds since the start of the epoch
|
||||
*
|
||||
* Generated from protobuf field <code>int64 seconds = 1;</code>
|
||||
* @param int|string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setSeconds($var)
|
||||
{
|
||||
GPBUtil::checkInt64($var);
|
||||
$this->seconds = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,166 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: Transaction.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.Transaction</code>
|
||||
*/
|
||||
class Transaction extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>uint64 id = 1;</code>
|
||||
*/
|
||||
private $id = 0;
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds received = 2;</code>
|
||||
*/
|
||||
private $received = null;
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.SignatureMap sigMap = 3;</code>
|
||||
*/
|
||||
private $sigMap = null;
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes txHash = 4;</code>
|
||||
*/
|
||||
private $txHash = '';
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes bodyBytes = 5;</code>
|
||||
*/
|
||||
private $bodyBytes = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type int|string $id
|
||||
* @type \Model\Messages\Gradido\TimestampSeconds $received
|
||||
* @type \Model\Messages\Gradido\SignatureMap $sigMap
|
||||
* @type string $txHash
|
||||
* @type string $bodyBytes
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\Transaction::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>uint64 id = 1;</code>
|
||||
* @return int|string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>uint64 id = 1;</code>
|
||||
* @param int|string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setId($var)
|
||||
{
|
||||
GPBUtil::checkUint64($var);
|
||||
$this->id = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds received = 2;</code>
|
||||
* @return \Model\Messages\Gradido\TimestampSeconds
|
||||
*/
|
||||
public function getReceived()
|
||||
{
|
||||
return $this->received;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds received = 2;</code>
|
||||
* @param \Model\Messages\Gradido\TimestampSeconds $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setReceived($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TimestampSeconds::class);
|
||||
$this->received = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.SignatureMap sigMap = 3;</code>
|
||||
* @return \Model\Messages\Gradido\SignatureMap
|
||||
*/
|
||||
public function getSigMap()
|
||||
{
|
||||
return $this->sigMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.SignatureMap sigMap = 3;</code>
|
||||
* @param \Model\Messages\Gradido\SignatureMap $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setSigMap($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\SignatureMap::class);
|
||||
$this->sigMap = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes txHash = 4;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getTxHash()
|
||||
{
|
||||
return $this->txHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes txHash = 4;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setTxHash($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->txHash = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes bodyBytes = 5;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getBodyBytes()
|
||||
{
|
||||
return $this->bodyBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>bytes bodyBytes = 5;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setBodyBytes($var)
|
||||
{
|
||||
GPBUtil::checkString($var, False);
|
||||
$this->bodyBytes = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,193 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: TransactionBody.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.TransactionBody</code>
|
||||
*/
|
||||
class TransactionBody extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* max 150 chars
|
||||
*
|
||||
* Generated from protobuf field <code>string memo = 1;</code>
|
||||
*/
|
||||
private $memo = '';
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds created = 2;</code>
|
||||
*/
|
||||
private $created = null;
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $memo
|
||||
* max 150 chars
|
||||
* @type \Model\Messages\Gradido\TimestampSeconds $created
|
||||
* @type \Model\Messages\Gradido\StateCreateGroup $createGroup
|
||||
* @type \Model\Messages\Gradido\StateGroupChangeParent $groupChangeParent
|
||||
* @type \Model\Messages\Gradido\Transfer $transfer
|
||||
* @type \Model\Messages\Gradido\TransactionCreation $creation
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\TransactionBody::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* max 150 chars
|
||||
*
|
||||
* Generated from protobuf field <code>string memo = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getMemo()
|
||||
{
|
||||
return $this->memo;
|
||||
}
|
||||
|
||||
/**
|
||||
* max 150 chars
|
||||
*
|
||||
* Generated from protobuf field <code>string memo = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setMemo($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->memo = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds created = 2;</code>
|
||||
* @return \Model\Messages\Gradido\TimestampSeconds
|
||||
*/
|
||||
public function getCreated()
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds created = 2;</code>
|
||||
* @param \Model\Messages\Gradido\TimestampSeconds $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreated($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TimestampSeconds::class);
|
||||
$this->created = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.StateCreateGroup createGroup = 6;</code>
|
||||
* @return \Model\Messages\Gradido\StateCreateGroup
|
||||
*/
|
||||
public function getCreateGroup()
|
||||
{
|
||||
return $this->readOneof(6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.StateCreateGroup createGroup = 6;</code>
|
||||
* @param \Model\Messages\Gradido\StateCreateGroup $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreateGroup($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\StateCreateGroup::class);
|
||||
$this->writeOneof(6, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.StateGroupChangeParent groupChangeParent = 7;</code>
|
||||
* @return \Model\Messages\Gradido\StateGroupChangeParent
|
||||
*/
|
||||
public function getGroupChangeParent()
|
||||
{
|
||||
return $this->readOneof(7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.StateGroupChangeParent groupChangeParent = 7;</code>
|
||||
* @param \Model\Messages\Gradido\StateGroupChangeParent $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupChangeParent($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\StateGroupChangeParent::class);
|
||||
$this->writeOneof(7, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Transfer transfer = 8;</code>
|
||||
* @return \Model\Messages\Gradido\Transfer
|
||||
*/
|
||||
public function getTransfer()
|
||||
{
|
||||
return $this->readOneof(8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.Transfer transfer = 8;</code>
|
||||
* @param \Model\Messages\Gradido\Transfer $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setTransfer($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Transfer::class);
|
||||
$this->writeOneof(8, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TransactionCreation creation = 9;</code>
|
||||
* @return \Model\Messages\Gradido\TransactionCreation
|
||||
*/
|
||||
public function getCreation()
|
||||
{
|
||||
return $this->readOneof(9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TransactionCreation creation = 9;</code>
|
||||
* @param \Model\Messages\Gradido\TransactionCreation $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreation($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TransactionCreation::class);
|
||||
$this->writeOneof(9, $var);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->whichOneof("data");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,136 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: TransactionCreation.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* need signature from group admin or
|
||||
* percent of group users another than the receiver
|
||||
*
|
||||
* Generated from protobuf message <code>model.messages.gradido.TransactionCreation</code>
|
||||
*/
|
||||
class TransactionCreation extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* 40 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
|
||||
*/
|
||||
private $receiverAmount = null;
|
||||
/**
|
||||
* 4 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
|
||||
*/
|
||||
private $ident_hash = 0;
|
||||
/**
|
||||
* 8 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
|
||||
*/
|
||||
private $target_date = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type \Model\Messages\Gradido\ReceiverAmount $receiverAmount
|
||||
* 40 Byte
|
||||
* @type int $ident_hash
|
||||
* 4 Byte
|
||||
* @type \Model\Messages\Gradido\TimestampSeconds $target_date
|
||||
* 8 Byte
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\TransactionCreation::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 40 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
|
||||
* @return \Model\Messages\Gradido\ReceiverAmount
|
||||
*/
|
||||
public function getReceiverAmount()
|
||||
{
|
||||
return $this->receiverAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 40 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
|
||||
* @param \Model\Messages\Gradido\ReceiverAmount $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setReceiverAmount($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\ReceiverAmount::class);
|
||||
$this->receiverAmount = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 4 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
|
||||
* @return int
|
||||
*/
|
||||
public function getIdentHash()
|
||||
{
|
||||
return $this->ident_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* 4 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
|
||||
* @param int $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setIdentHash($var)
|
||||
{
|
||||
GPBUtil::checkInt32($var);
|
||||
$this->ident_hash = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 8 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
|
||||
* @return \Model\Messages\Gradido\TimestampSeconds
|
||||
*/
|
||||
public function getTargetDate()
|
||||
{
|
||||
return $this->target_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 8 Byte
|
||||
*
|
||||
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
|
||||
* @param \Model\Messages\Gradido\TimestampSeconds $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setTargetDate($var)
|
||||
{
|
||||
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TimestampSeconds::class);
|
||||
$this->target_date = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: Transfer.proto
|
||||
|
||||
namespace Model\Messages\Gradido;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\RepeatedField;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
|
||||
/**
|
||||
* Generated from protobuf message <code>model.messages.gradido.Transfer</code>
|
||||
*/
|
||||
class Transfer extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.SenderAmount senderAmounts = 1;</code>
|
||||
*/
|
||||
private $senderAmounts;
|
||||
/**
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.ReceiverAmount receiverAmounts = 2;</code>
|
||||
*/
|
||||
private $receiverAmounts;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type \Model\Messages\Gradido\SenderAmount[]|\Google\Protobuf\Internal\RepeatedField $senderAmounts
|
||||
* @type \Model\Messages\Gradido\ReceiverAmount[]|\Google\Protobuf\Internal\RepeatedField $receiverAmounts
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GPBMetadata\Transfer::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.SenderAmount senderAmounts = 1;</code>
|
||||
* @return \Google\Protobuf\Internal\RepeatedField
|
||||
*/
|
||||
public function getSenderAmounts()
|
||||
{
|
||||
return $this->senderAmounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.SenderAmount senderAmounts = 1;</code>
|
||||
* @param \Model\Messages\Gradido\SenderAmount[]|\Google\Protobuf\Internal\RepeatedField $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setSenderAmounts($var)
|
||||
{
|
||||
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Model\Messages\Gradido\SenderAmount::class);
|
||||
$this->senderAmounts = $arr;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.ReceiverAmount receiverAmounts = 2;</code>
|
||||
* @return \Google\Protobuf\Internal\RepeatedField
|
||||
*/
|
||||
public function getReceiverAmounts()
|
||||
{
|
||||
return $this->receiverAmounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>repeated .model.messages.gradido.ReceiverAmount receiverAmounts = 2;</code>
|
||||
* @param \Model\Messages\Gradido\ReceiverAmount[]|\Google\Protobuf\Internal\RepeatedField $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setReceiverAmounts($var)
|
||||
{
|
||||
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Model\Messages\Gradido\ReceiverAmount::class);
|
||||
$this->receiverAmounts = $arr;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -188,20 +188,28 @@ class TransactionsTable extends Table
|
||||
if($prev && $decay == true)
|
||||
{
|
||||
if($prev->balance > 0) {
|
||||
$current = $su_transaction;
|
||||
$current = $su_transaction;
|
||||
$calculated_decay = $stateBalancesTable->calculateDecay($prev->balance, $prev->balance_date, $current->balance_date, true);
|
||||
$balance = floatval($prev->balance - $calculated_decay['balance']);
|
||||
$balance = floatval($prev->balance - $calculated_decay['balance']);
|
||||
|
||||
// skip small decays (smaller than 0,00 GDD)
|
||||
if(abs($balance) >= 100) {
|
||||
$final_transaction['decay'] = [
|
||||
'balance' => $balance,
|
||||
'decay_duration' => $calculated_decay['interval']->format('%a days, %H hours, %I minutes, %S seconds')
|
||||
];
|
||||
if($balance)
|
||||
{
|
||||
$final_transactions['decay'] = [
|
||||
'balance' => $balance,
|
||||
'decay_duration' => $calculated_decay['interval']->format('%a days, %H hours, %I minutes, %S seconds')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sender or receiver when user has sended money
|
||||
// group name if creation
|
||||
// type: gesendet / empfangen / geschöpft
|
||||
// transaktion nr / id
|
||||
// date
|
||||
// balance
|
||||
$transaction = $transaction_indiced[$su_transaction->transaction_id];
|
||||
|
||||
if($su_transaction->transaction_type_id == 1) { // creation
|
||||
$creation = $transaction->transaction_creation;
|
||||
$balance = $stateBalancesTable->calculateDecay($creation->amount, $creation->target_date, $transaction->received);
|
||||
|
||||
@ -25,7 +25,7 @@ class Transaction extends TransactionBase {
|
||||
//$transactionBin = base64_decode($base64Data, true);
|
||||
//if($transactionBin == false) {
|
||||
//sodium_base64_VARIANT_URLSAFE_NO_PADDING
|
||||
if(is_a($base64Data, '\Proto\Gradido\Transaction')) {
|
||||
if(is_a($base64Data, '\Proto\Gradido\GradidoTransaction')) {
|
||||
$this->mProtoTransaction = $base64Data;
|
||||
$this->mTransactionBody = new TransactionBody($this->mProtoTransaction->getBodyBytes());
|
||||
return;
|
||||
@ -93,7 +93,11 @@ class Transaction extends TransactionBase {
|
||||
return $this->mTransactionBody;
|
||||
}
|
||||
|
||||
public function getFirstPublic() {
|
||||
public function getFirstPublic()
|
||||
{
|
||||
if(!$this->mProtoTransaction || !$this->mProtoTransaction->getSigMap()) {
|
||||
return '';
|
||||
}
|
||||
$sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair();
|
||||
return $sigPairs[0]->getPubKey();
|
||||
}
|
||||
@ -111,6 +115,7 @@ class Transaction extends TransactionBase {
|
||||
$sigMap = $this->mProtoTransaction->getSigMap();
|
||||
if(!$sigMap) {
|
||||
$this->addError('Transaction', 'signature map is zero');
|
||||
//var_dump($this->mProtoTransaction);
|
||||
return false;
|
||||
}
|
||||
//var_dump($sigMap);
|
||||
@ -193,8 +198,10 @@ class Transaction extends TransactionBase {
|
||||
|
||||
$connection->commit();
|
||||
|
||||
$this->mTransactionBody->getSpecificTransaction()->sendNotificationEmail($this->mTransactionBody->getMemo());
|
||||
$specificTransaction = $this->mTransactionBody->getSpecificTransaction();
|
||||
|
||||
$specificTransaction->sendNotificationEmail($this->mTransactionBody->getMemo());
|
||||
$this->addWarnings($specificTransaction->getWarnings());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -6,29 +6,43 @@ use Cake\ORM\TableRegistry;
|
||||
|
||||
class TransactionBase {
|
||||
private $errors = [];
|
||||
private $warnings = [];
|
||||
static $tables = [];
|
||||
|
||||
public function getErrors() {
|
||||
return $this->errors;
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function getWarnings() {
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
public function addError($functionName, $errorName) {
|
||||
array_push($this->errors, [$functionName => $errorName]);
|
||||
array_push($this->errors, [$functionName => $errorName]);
|
||||
}
|
||||
public function addWarning($functionName, $warningName) {
|
||||
array_push($this->warnings, [$functionName => $warningName]);
|
||||
}
|
||||
|
||||
public function addErrors($errors) {
|
||||
$this->errors = array_merge($this->errors, $errors);
|
||||
$this->errors = array_merge($this->errors, $errors);
|
||||
}
|
||||
|
||||
public function addWarnings($warnings) {
|
||||
$this->warnings = array_merge($this->warnings, $warnings);
|
||||
}
|
||||
|
||||
public function hasErrors() {
|
||||
return count($this->errors) > 0;
|
||||
return count($this->errors) > 0;
|
||||
}
|
||||
|
||||
public function hasWarnings() {
|
||||
return count($this->warnings) > 0;
|
||||
}
|
||||
public static function getTable($tableName) {
|
||||
if(!isset(self::$tables[$tableName])) {
|
||||
self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName);
|
||||
}
|
||||
return self::$tables[$tableName];
|
||||
if(!isset(self::$tables[$tableName])) {
|
||||
self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName);
|
||||
}
|
||||
return self::$tables[$tableName];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -209,6 +209,7 @@ class TransactionCreation extends TransactionBase {
|
||||
->send();
|
||||
} catch(Exception $e) {
|
||||
// $this->addError('TransactionCreation::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage());
|
||||
$this->addWarning('TransactionCreation::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -58,7 +58,7 @@ class TransactionTransfer extends TransactionBase {
|
||||
//$this->addError('TransactionTransfer::validate', 'not implemented yet');
|
||||
//return false;
|
||||
//$time = microtime(true);
|
||||
static $functionName = 'TransactionCreation::validate';
|
||||
static $functionName = 'TransactionTransfer::validate';
|
||||
|
||||
$sigPubHexs = [];
|
||||
foreach($sigPairs as $sigPair)
|
||||
@ -204,13 +204,14 @@ class TransactionTransfer extends TransactionBase {
|
||||
$this->addError('TransactionCreation::sendNotificationEmail', 'to email is empty for user: ' . $receiverUser->id);
|
||||
return false;
|
||||
}
|
||||
$email->setFrom([$serverAdminEmail => $senderUser->getNames() . ' via Gradido Community'])
|
||||
$noReplyEmail = Configure::read('noReplyEmail');
|
||||
$email->setFrom([$noReplyEmail => 'Gradido (nicht antworten)'])
|
||||
->setTo([$receiverUser->email => $receiverUser->getNames()])
|
||||
->setReplyTo($senderUser->email)
|
||||
->setSubject(__('Gradidos erhalten'))
|
||||
->send();
|
||||
} catch(Exception $e) {
|
||||
//$this->addError('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage());
|
||||
$this->addWarning('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -15,7 +15,7 @@ $senderNames = $senderUser->first_name . ' ' . $senderUser->last_name;
|
||||
|
||||
<?= $memo ?>
|
||||
|
||||
<?= __('Du kannst {0} eine Nachricht schreiben, indem du auf diese E-Mail antwortest', $senderNames); ?>
|
||||
<?= __('Bitte antworte nicht auf diese E-Mail!'); ?>
|
||||
|
||||
<?= __('Mit freundlichen Grüßen'); ?>
|
||||
Gradido Community Server
|
||||
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
$this->loadHelper('Form', [
|
||||
'templates' => 'horizontal_form',
|
||||
]);
|
||||
$now = new \DateTime;
|
||||
?>
|
||||
<?php if(isset($errors) && count($errors) > 0) : ?>
|
||||
<div class="alert-color">
|
||||
<ul>
|
||||
<?php foreach($errors as $error) : ?>
|
||||
<li>
|
||||
<?= var_dump($error); ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="action-form">
|
||||
<p class="form-header"><?= __('Creation Transaction') ?></p>
|
||||
<div class="form-body">
|
||||
<?= $this->Form->create() ?>
|
||||
<?= $this->Form->control('type', ['type' => 'hidden', 'value' => 'creation']) ?>
|
||||
<?= $this->Form->control('target_public_key', ['type'=> 'text']) ?>
|
||||
<?= $this->Form->control('target_date', ['type'=> 'text', 'placeholder' => 'yyyy-mm-dd hh:ii:ss', 'default' => $now->format('Y-m-d H:i:s')]) ?>
|
||||
<?= $this->Form->control('amount', ['type'=> 'number']) ?>
|
||||
<?= $this->Form->control('memo', ['type'=> 'textarea', 'rows' => '8', 'cols' => 40]) ?>
|
||||
<?= $this->Form->control('signer_public_key', ['type' => 'text']) ?>
|
||||
<?= $this->Form->control('signer_private_key', ['type'=> 'text']) ?>
|
||||
<?= $this->Form->submit(); ?>
|
||||
<?= $this->Form->end() ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-form">
|
||||
<p class="form-header"><?= __('Transfer Transaction') ?></p>
|
||||
<div class="form-body">
|
||||
<?= $this->Form->create() ?>
|
||||
<?= $this->Form->control('type', ['type' => 'hidden', 'value' => 'transfer']) ?>
|
||||
<?= $this->Form->control('sender_public_key', ['type'=> 'text']) ?>
|
||||
<?= $this->Form->control('receiver_public_key', ['type'=> 'text']) ?>
|
||||
<?= $this->Form->control('amount', ['type'=> 'number']) ?>
|
||||
<?= $this->Form->control('memo', ['type'=> 'textarea', 'rows' => '8', 'cols' => 40]) ?>
|
||||
<?= $this->Form->control('signer_public_key', ['type' => 'text']) ?>
|
||||
<?= $this->Form->control('signer_private_key', ['type'=> 'text']) ?>
|
||||
<?= $this->Form->submit(); ?>
|
||||
<?= $this->Form->end() ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if(isset($base64)) : ?>
|
||||
<div>
|
||||
<ul>
|
||||
<?php foreach($base64 as $name => $value) : ?>
|
||||
<li><?= $name ?>: <?= $value ?></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
@ -23,8 +23,7 @@ class CommunityProfilesFixture extends TestFixture
|
||||
'state_user_id' => ['type' => 'index', 'columns' => ['state_user_id'], 'length' => []],
|
||||
],
|
||||
'_constraints' => [
|
||||
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
|
||||
'community_profiles_ibfk_1' => ['type' => 'foreign', 'columns' => ['state_user_id'], 'references' => ['state_users', 'id'], 'update' => 'restrict', 'delete' => 'restrict', 'length' => []],
|
||||
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []]
|
||||
],
|
||||
'_options' => [
|
||||
'engine' => 'InnoDB',
|
||||
|
||||
45
community_server/tests/Fixture/Migrations2Fixture.php
Normal file
45
community_server/tests/Fixture/Migrations2Fixture.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace App\Test\Fixture;
|
||||
|
||||
use Cake\TestSuite\Fixture\TestFixture;
|
||||
|
||||
/**
|
||||
* MigrationsFixture
|
||||
*/
|
||||
class Migrations2Fixture extends TestFixture
|
||||
{
|
||||
/**
|
||||
* Fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
// @codingStandardsIgnoreStart
|
||||
public $fields = [
|
||||
'id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
|
||||
'db_version' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => true, 'default' => '0', 'comment' => '', 'precision' => null, 'autoIncrement' => null],
|
||||
'_constraints' => [
|
||||
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
|
||||
],
|
||||
'_options' => [
|
||||
'engine' => 'InnoDB',
|
||||
'collation' => 'utf8mb4_unicode_ci'
|
||||
],
|
||||
];
|
||||
// @codingStandardsIgnoreEnd
|
||||
/**
|
||||
* Init method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->table = "migrations";
|
||||
$this->records = [
|
||||
[
|
||||
'id' => 1,
|
||||
'db_version' => 2,
|
||||
],
|
||||
];
|
||||
parent::init();
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@ use Cake\TestSuite\Fixture\TestFixture;
|
||||
/**
|
||||
* StateBalancesFixture
|
||||
*/
|
||||
class StateBalancesFixture extends TestFixture
|
||||
class StateBalancesFixture extends BaseTestFixture
|
||||
{
|
||||
/**
|
||||
* Fields
|
||||
@ -36,8 +36,11 @@ class StateBalancesFixture extends TestFixture
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->records = [
|
||||
$sql = [
|
||||
[4, 4, '2021-05-27 17:47:50', '2021-05-27 17:47:50', 28808497],
|
||||
[5, 1, '2021-05-27 17:47:51', '2021-05-27 17:47:50', 9823963]
|
||||
];
|
||||
$this->records = $this->sqlEntrysToRecords($sql, $this->fields);
|
||||
parent::init();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
<?php
|
||||
namespace App\Test\Fixture;
|
||||
|
||||
use Cake\TestSuite\Fixture\TestFixture;
|
||||
|
||||
/**
|
||||
* TransactionCreationsFixture
|
||||
*/
|
||||
@ -19,7 +17,6 @@ class TransactionCreationsFixture extends BaseTestFixture
|
||||
'transaction_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
|
||||
'state_user_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
|
||||
'amount' => ['type' => 'biginteger', 'length' => 20, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
|
||||
'ident_hash' => ['type' => 'binary', 'length' => 32, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null],
|
||||
'target_date' => ['type' => 'timestamp', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null],
|
||||
'_constraints' => [
|
||||
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
|
||||
@ -37,9 +34,9 @@ class TransactionCreationsFixture extends BaseTestFixture
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$sql = [
|
||||
[2, 1, 4, 10000000, '0000000000000000000000000000000000000000000000000000000000000000', '2021-01-01 00:00:00'],
|
||||
[3, 2, 1, 10000000, '0000000000000000000000000000000000000000000000000000000000000000', '2021-01-01 00:00:00']
|
||||
$sql = [
|
||||
[2, 1, 4, 10000000, '2021-01-01 00:00:00'],
|
||||
[3, 2, 1, 10000000, '2021-01-01 00:00:00']
|
||||
];
|
||||
$this->records = $this->sqlEntrysToRecords($sql, $this->fields);
|
||||
parent::init();
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
namespace App\Test\TestCase\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\TestSuite\IntegrationTestTrait;
|
||||
use Cake\TestSuite\TestCase;
|
||||
|
||||
/**
|
||||
* App\Controller\DashboardController Test Case
|
||||
*
|
||||
* @uses \App\Controller\DashboardController
|
||||
*/
|
||||
class AppControllerTest extends TestCase
|
||||
{
|
||||
use IntegrationTestTrait;
|
||||
|
||||
/**
|
||||
* Fixtures
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fixtures = [
|
||||
'app.StateBalances'
|
||||
];
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test initialize method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInitialize()
|
||||
{
|
||||
$this->session(['StateUser.id' => 1]);
|
||||
$this->get('/');
|
||||
$this->assertSession(1200, 'StateUser.balance');
|
||||
//$this->markTestIncomplete('Not implemented yet.');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,303 @@
|
||||
<?php
|
||||
namespace App\Test\TestCase\Controller;
|
||||
|
||||
use Cake\TestSuite\IntegrationTestTrait;
|
||||
use Cake\TestSuite\TestCase;
|
||||
|
||||
/**
|
||||
* App\Controller\AppRequestsController Test Case
|
||||
*
|
||||
* @uses \App\Controller\AppRequestsController
|
||||
*/
|
||||
class AppRequestControllerTest extends TestCase
|
||||
{
|
||||
use IntegrationTestTrait;
|
||||
|
||||
/**
|
||||
* Fixtures
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fixtures = [
|
||||
'app.TransactionCreations',
|
||||
'app.Transactions',
|
||||
'app.StateUsers',
|
||||
'app.StateUserTransactions',
|
||||
'app.StateErrors',
|
||||
'app.TransactionSignatures',
|
||||
'app.TransactionSendCoins',
|
||||
'app.StateBalances',
|
||||
'app.TransactionTypes',
|
||||
'app.Migrations'
|
||||
];
|
||||
|
||||
|
||||
|
||||
/*public function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Test ajaxGetBalance method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetBalance1()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 1,
|
||||
'email_checked' => 1,
|
||||
'public_hex' => 'f7f4a49a4ac10379f8b9ddcb731c4d9ec495e6edd16075f52672cd25e3179f0f'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->getAndParseWithoutCompare('/api/get-balance/' . $session_id);
|
||||
$this->assertEquals('success', $response->state);
|
||||
$this->assertEquals(9100000, $response->balance);
|
||||
$this->assertLessThan(9100000, $response->decay);
|
||||
|
||||
}
|
||||
|
||||
public function testGetBalance2()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 3,
|
||||
'email_checked' => 1,
|
||||
'public_hex' => '131c7f68dd94b2be4c913400ff7ff4cdc03ac2bda99c2d29edcacb3b065c67e6'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->getAndParseWithoutCompare('/api/get-balance/' . $session_id);
|
||||
$this->assertEquals('success', $response->state);
|
||||
$this->assertEquals(0, $response->balance);
|
||||
}
|
||||
public function testGetBalance3()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 4,
|
||||
'email_checked' => 1,
|
||||
'public_hex' => 'e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->getAndParseWithoutCompare('/api/get-balance/' . $session_id);
|
||||
$this->assertEquals('success', $response->state);
|
||||
$this->assertEquals(10900000, $response->balance);
|
||||
$this->assertLessThan(10900000, $response->decay);
|
||||
}
|
||||
|
||||
public function testGetBalanceInvalidSession()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'email_checked' => 1,
|
||||
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->getAndParse('/api/get-balance/' . 1211,
|
||||
['state' => 'not found', 'msg' => 'invalid session']
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetBalanceInvalidSessionId()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'email_checked' => 1,
|
||||
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->getAndParse('/api/get-balance/' ,
|
||||
['state' => 'not found', 'msg' => 'invalid session']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ajaxListTransactions method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testListTransactions()
|
||||
{
|
||||
//ajaxListTransactions
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transactions' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 1,
|
||||
'first_name' => 'Dario',
|
||||
'last_name' => 'Frodo',
|
||||
'email_checked' => 1,
|
||||
'email' => 'fördertest@gradido.org',
|
||||
'public_hex' => '94ae135b93cd9f33752b4e55c41903a3faa13a75bb90bfd411ea1d4a1a5e711f'
|
||||
]
|
||||
]);
|
||||
//echo "balance: $balance";
|
||||
$expectedResult = '{
|
||||
"state": "success",
|
||||
"transactions": [
|
||||
{
|
||||
"name": "Gradido Akademie",
|
||||
"type": "creation",
|
||||
"transaction_id": 2,
|
||||
"date": "2021-04-12T00:00:00+00:00",
|
||||
"target_date": "2021-01-01T00:00:00+00:00",
|
||||
"creation_amount": 10000000,
|
||||
"balance": 10000000,
|
||||
"memo": "AGE Januar 2021"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Schmied",
|
||||
"email": "test3.yahoo.com",
|
||||
"type": "send",
|
||||
"transaction_id": 3,
|
||||
"date": "2021-04-12T00:00:00+00:00",
|
||||
"balance": 1000000,
|
||||
"memo": "test",
|
||||
"pubkey": "e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Schmied",
|
||||
"email": "test3.yahoo.com",
|
||||
"type": "send",
|
||||
"transaction_id": 4,
|
||||
"date": "2021-04-14T00:00:00+00:00",
|
||||
"balance": 100000,
|
||||
"memo": "test time",
|
||||
"pubkey": "e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Schmied",
|
||||
"email": "test3.yahoo.com",
|
||||
"type": "send",
|
||||
"transaction_id": 5,
|
||||
"date": "2021-04-14T09:01:07+00:00",
|
||||
"balance": 100000,
|
||||
"memo": "test time",
|
||||
"pubkey": "e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Schmied",
|
||||
"email": "test3.yahoo.com",
|
||||
"type": "receive",
|
||||
"transaction_id": 6,
|
||||
"date": "2021-04-14T09:02:28+00:00",
|
||||
"balance": 100000,
|
||||
"memo": "test time 3",
|
||||
"pubkey": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Schmied",
|
||||
"email": "test3.yahoo.com",
|
||||
"type": "receive",
|
||||
"transaction_id": 7,
|
||||
"date": "2021-04-14T09:28:46+00:00",
|
||||
"balance": 100000,
|
||||
"memo": "test login crash",
|
||||
"pubkey": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Schmied",
|
||||
"email": "test3.yahoo.com",
|
||||
"type": "receive",
|
||||
"transaction_id": 8,
|
||||
"date": "2021-04-14T09:31:28+00:00",
|
||||
"balance": 100000,
|
||||
"memo": "test login crash",
|
||||
"pubkey": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
],
|
||||
"transactionExecutingCount": 0,
|
||||
"count": 7,
|
||||
"gdtSum": 180000,
|
||||
"timeUsed": 0.5575470924377441,
|
||||
"decay_date": "2021-05-28T09:35:02+00:00",
|
||||
"balance": 9100000,
|
||||
"decay": 9100000
|
||||
}';
|
||||
$this->getAndParse('/api/list-transactions/', json_decode($expectedResult, true));
|
||||
}
|
||||
|
||||
|
||||
private function getAndParse($path, $expected)
|
||||
{
|
||||
$this->configRequest([
|
||||
'headers' => ['Accept' => 'application/json']
|
||||
]);
|
||||
|
||||
$this->disableErrorHandlerMiddleware();
|
||||
$this->get($path);
|
||||
|
||||
// Check that the response was in 2xx - 3xx
|
||||
$this->assertResponseSuccess();
|
||||
$json = (object)$this->viewVariable('body');
|
||||
|
||||
if(!$json) {
|
||||
// Check that the response was a 200
|
||||
$this->assertResponseOk();
|
||||
|
||||
$responseBodyString = (string)$this->_response->getBody();
|
||||
$json = json_decode($responseBodyString);
|
||||
$this->assertNotFalse($json);
|
||||
} else {
|
||||
$responseBodyString = json_encode($json);
|
||||
}
|
||||
|
||||
if(is_array($expected)) {
|
||||
$dynamic_fields = ['timeUsed', 'decay_date', 'decay', 'gdtSum'];
|
||||
// copy timeUsed because this value will be variy always
|
||||
foreach($dynamic_fields as $field) {
|
||||
if(isset($expected[$field]) && isset($json->$field)) {
|
||||
$expected[$field] = $json->$field;
|
||||
}
|
||||
}
|
||||
$expected = json_encode($expected);
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, $responseBodyString);
|
||||
}
|
||||
private function getAndParseWithoutCompare($path)
|
||||
{
|
||||
$this->configRequest([
|
||||
'headers' => ['Accept' => 'application/json']
|
||||
]);
|
||||
|
||||
$this->disableErrorHandlerMiddleware();
|
||||
$this->get($path);
|
||||
|
||||
// Check that the response was in 2xx - 3xx
|
||||
$this->assertResponseSuccess();
|
||||
$view_body = $this->viewVariable('body');
|
||||
if($view_body) {
|
||||
return (object)$view_body;
|
||||
}
|
||||
// Check that the response was a 200
|
||||
$this->assertResponseOk();
|
||||
$responseBodyString = (string)$this->_response->getBody();
|
||||
$json = json_decode($responseBodyString, true);
|
||||
$this->assertNotFalse($json);
|
||||
|
||||
return $json;
|
||||
}
|
||||
}
|
||||
@ -51,19 +51,7 @@ class JsonRequestClientComponentTest extends TestCase
|
||||
$this->markTestIncomplete('Not implemented yet.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getLoginServerUrl method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetLoginServerUrl()
|
||||
{
|
||||
//$this->markTestIncomplete('Not implemented yet.');
|
||||
$serverUrl = $this->JsonRequestClientComponent->getLoginServerUrl();
|
||||
$this->assertEquals($serverUrl, 'http://***REMOVED***');
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Test is_base64 method
|
||||
*
|
||||
* @return void
|
||||
|
||||
@ -5,9 +5,9 @@ use Cake\TestSuite\IntegrationTestTrait;
|
||||
use Cake\TestSuite\TestCase;
|
||||
|
||||
/**
|
||||
* App\Controller\TransactionJsonRequestHandlerController Test Case
|
||||
* App\Controller\JsonRequestHandlerController Test Case
|
||||
*
|
||||
* @uses \App\Controller\TransactionJsonRequestHandlerController
|
||||
* @uses \App\Controller\JsonRequestHandlerController
|
||||
*/
|
||||
class JsonRequestHandlerControllerTest extends TestCase
|
||||
{
|
||||
@ -22,6 +22,7 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
'app.TransactionCreations',
|
||||
'app.Transactions',
|
||||
'app.StateUsers',
|
||||
'app.StateUserTransactions',
|
||||
'app.StateErrors',
|
||||
'app.TransactionSignatures',
|
||||
'app.TransactionSendCoins',
|
||||
@ -30,13 +31,12 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
];
|
||||
|
||||
public $transactions = [
|
||||
'validCreation' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQJ8wF12eZo3hcMAlAKKJ9WLT-zuSkNmGh7D98UEqH4KoIysnCkXqEya9EBZl9o11_nJ8xmm_nOevuVjR-GfLMQ8qSQoOSGFsbG8gV2VsdCAxMjMSBgiZm4ruBUovCicKIJSuE1uTzZ8zdStOVcQZA6P6oTp1u5C_1BHqHUoaXnEfEKDakwEQtYntlgo',
|
||||
'validCreation900' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQNVZ8Ae3Zbg3G0wZ840fzKan6N4KtTcSe0KYi17kQwFmsl18oFxXv8_s6j1xXFrIKjy1_1Olq0a7xYLErDMkjwYqORIGCNb5iu4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgNHKCBC1ie2WCg',
|
||||
'validCreation1200' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQEEey5QMAdldoOTP_jTETHgOQriGsixEY0cziQeRfT_J5YtbI_A6AizEYD-JcxmRmXzv1xjjTgsV39Y32ta2CQkqORIGCIeGi-4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgOy4CxC1ie2WCg',
|
||||
'validCreation' => 'CmYKZAog4zad42I86ERtBCTEAT56HXGiZxrj178eeY6_BmXRRfISQDnatUMvitiiP0-sY93JStYPhPKKPU4Vosv_EGrh77BVs48xhPgPj2QHWC3oyuuMh6nN8YNjBQZx20rKvdQ4uwMSRwoMQUdFIE1haSAyMDIxEgYI_c3ChQY6LwolCiD39KSaSsEDefi53ctzHE2exJXm7dFgdfUmcs0l4xefDxDQDxoGCPqbtIQG',
|
||||
'validCreation900' => 'CmYKZAog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8SQCaZHmvmvJOt336E3qst3rn1pptdAR5ZPzePaUT10x0_Yky8FnEiQtMGNy1yT94QErzwQudJZjJwDY2uyK4cTgkSOxIGCKb1vYUGOjEKJwog4zad42I86ERtBCTEAT56HXGiZxrj178eeY6_BmXRRfIQgNHKCBoGCIDMuf8F',
|
||||
'validCreation1200' => 'CmYKZAog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8SQF8jptIrosEyVmCf3WEIGVOK0NR8YCcO0j-s8v2yUyR5BKus0ciT6B7IA5LDtn7eQX6zHjg1v5WlsTiZuOpuNgwSRAoHVG8gbXVjaBIGCL3Jv4UGOjEKJwog4zad42I86ERtBCTEAT56HXGiZxrj178eeY6_BmXRRfIQgOy4CxoGCOG5toQG',
|
||||
'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3',
|
||||
'validTransfer' => 'GmYKZAoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0SQDddHyKzAX3LBV0PuDiPc6lxkUipss5tyuLRpMtFJQnT30tsbYIkA1FXimjMKOoiuLswf4OLLV3bAIYehW-b9AgqYQoFSGFsbG8SBgiJlaPvBUJQCiYKIIGQvaWF7l8dn799BugeaewY4TN2EEz_VLdFfrfT73ENEICfSRImCiDtdleSLxhUgEbMW9DpqIwsykFj3-z_enKEOuGnXrmW8xCAn0k',
|
||||
'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ==',
|
||||
'creationValid' => 'GmYKZAogLtKKHPXhFtg2FUBrxXcVIiHC93SlZW9moOdUD3V21xsSQHpXYAGiVmSfhjB3o7OPx0ZJuPXrDk5eu1_AOhQBODU3KpUqBRA9yMX54S_mvGijGubCNRcMLcm7wiYbyAG-3AkqSwoQZWluIE1vbmF0c2dlaGFsdBIGCKqs5vEFSi8KJwoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0QgNrECRDKyd3uAQ'
|
||||
'validTransfer' => 'CmYKZAog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8SQA0ZVQ9T1qBabzmgDO1NAWNy2J6mlv0YjMP99CiV7bSR0zemt5XoM-kTviR1aTqKggzpSYSyTN5T6gIx2xa-hgkSYwoLTXkgQmlydGhkYXkSBgie0L-FBjJMCkoKJgog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8QgIl6EiDjNp3jYjzoRG0EJMQBPnodcaJnGuPXvx55jr8GZdFF8g',
|
||||
'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ=='
|
||||
];
|
||||
|
||||
/*public function setUp() {
|
||||
@ -51,7 +51,7 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
$this->get('/JsonRequestHandler');
|
||||
$this->assertResponseOk();
|
||||
|
||||
$expected = json_encode(['state' => 'error', 'msg' => 'no post']);
|
||||
$expected = json_encode(['state' => 'error', 'msg' => 'unknown method for get', 'details' => null]);
|
||||
$this->assertEquals($expected, (string)$this->_response->getBody());
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
//$this->post('/TransactionJsonRequestHandler', ['method' => 'putTransaction', 'transaction' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3/cHHaWchkUhWiGhQjB23xCg2pMBELWJ7ZYK']);
|
||||
$this->postAndParse(
|
||||
['method' => 'foobar', 'transaction' => $this->transactions['validCreation']],
|
||||
['state' => 'error', 'msg' => 'unknown method', 'details' => 'foobar']
|
||||
['state' => 'error', 'msg' => 'unknown method for post', 'details' => 'foobar']
|
||||
);
|
||||
|
||||
}
|
||||
@ -97,7 +97,8 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['notBase64']],
|
||||
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
|
||||
['Transaction' => 'invalid base64 string']
|
||||
['Transaction' => 'invalid base64 string'],
|
||||
['base64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3']
|
||||
]]
|
||||
);
|
||||
}
|
||||
@ -114,9 +115,10 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
|
||||
public function testToLargeCreationSum()
|
||||
{
|
||||
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation900']],
|
||||
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
|
||||
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1.000 GDD per Month for in target_date not allowed"}]}'
|
||||
);
|
||||
}
|
||||
|
||||
@ -124,49 +126,36 @@ class JsonRequestHandlerControllerTest extends TestCase
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation1200']],
|
||||
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
|
||||
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1.000 GDD per Month for in target_date not allowed"}]}'
|
||||
);
|
||||
}
|
||||
|
||||
public function testValidTransfer()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']],
|
||||
['state' => 'success']
|
||||
);
|
||||
}
|
||||
|
||||
/*public function testMissingPreviousTransaction()
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
public function testValidTransaction()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
|
||||
['state' => 'success']
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']],
|
||||
['state' => 'success']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testValidCreation()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['creationValid']],
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
|
||||
['state' => 'success']
|
||||
);
|
||||
}
|
||||
|
||||
private function postAndParse($params, $expected)
|
||||
{
|
||||
//$this->enableCsrfToken();
|
||||
$this->enableCsrfToken();
|
||||
//$this->enableSecurityToken();
|
||||
|
||||
$token = 'my-csrf-token';
|
||||
$this->cookie('csrfToken', $token);
|
||||
//$token = 'my-csrf-token';
|
||||
//$this->cookie('csrfToken', $token);
|
||||
|
||||
$this->configRequest([
|
||||
'headers' => ['Accept' => 'application/json', 'X-CSRF-Token' => $token]
|
||||
'headers' => ['Accept' => 'application/json']//, 'X-CSRF-Token' => $token]
|
||||
]);
|
||||
|
||||
$this->disableErrorHandlerMiddleware();
|
||||
|
||||
@ -27,6 +27,10 @@ use Cake\View\Exception\MissingTemplateException;
|
||||
*/
|
||||
class PagesControllerTest extends IntegrationTestCase
|
||||
{
|
||||
|
||||
public $fixtures = [
|
||||
'app.Migrations2'
|
||||
];
|
||||
/**
|
||||
* testMultipleGet method
|
||||
*
|
||||
@ -35,9 +39,12 @@ class PagesControllerTest extends IntegrationTestCase
|
||||
public function testMultipleGet()
|
||||
{
|
||||
$this->get('/');
|
||||
$this->assertRedirect('account/');
|
||||
$locations = $this->_response->getHeader('Location');
|
||||
$this->assertRegExp('%.*/account/$%', $locations[0]);
|
||||
|
||||
$this->get('/');
|
||||
$this->assertRedirect('account/');
|
||||
$locations = $this->_response->getHeader('Location');
|
||||
$this->assertRegExp('%.*/account/$%', $locations[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,7 +71,7 @@ class PagesControllerTest extends IntegrationTestCase
|
||||
$this->get('/pages/not_existing');
|
||||
|
||||
$this->assertResponseError();
|
||||
$this->assertResponseContains('Error');
|
||||
$this->assertResponseContains('Not Found');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,8 +85,7 @@ class PagesControllerTest extends IntegrationTestCase
|
||||
$this->get('/pages/not_existing');
|
||||
|
||||
$this->assertResponseFailure();
|
||||
$this->assertResponseContains('Missing Template');
|
||||
$this->assertResponseContains('Stacktrace');
|
||||
$this->assertResponseContains('Template file \u0022Pages\/not_existing.ctp\u0022 is missing.');
|
||||
$this->assertResponseContains('not_existing.ctp');
|
||||
}
|
||||
|
||||
|
||||
@ -69,142 +69,7 @@ class StateBalancesControllerTest extends TestCase
|
||||
$this->markTestIncomplete('Not implemented yet.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ajaxGetBalance method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAjaxGetBalance1()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 1,
|
||||
'email_checked' => 1,
|
||||
'public_hex' => 'f7f4a49a4ac10379f8b9ddcb731c4d9ec495e6edd16075f52672cd25e3179f0f'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->getAndParseWithoutCompare('/state-balances/ajaxGetBalance/' . $session_id);
|
||||
|
||||
$this->assertEquals('success', $response->state);
|
||||
$this->assertEquals(7321825, $response->balance);
|
||||
$this->assertLessThan(7321825, $response->decay);
|
||||
|
||||
}
|
||||
|
||||
public function testAjaxGetBalance2()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 3,
|
||||
'email_checked' => 1,
|
||||
'public_hex' => '131c7f68dd94b2be4c913400ff7ff4cdc03ac2bda99c2d29edcacb3b065c67e6'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->getAndParseWithoutCompare('/state-balances/ajaxGetBalance/' . $session_id);
|
||||
$this->assertEquals('success', $response->state);
|
||||
$this->assertEquals(0, $response->balance);
|
||||
}
|
||||
public function testAjaxGetBalance3()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 4,
|
||||
'email_checked' => 1,
|
||||
'public_hex' => 'e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->getAndParseWithoutCompare('/state-balances/ajaxGetBalance/' . $session_id);
|
||||
$this->assertEquals('success', $response->state);
|
||||
$this->assertEquals(9112592, $response->balance);
|
||||
$this->assertLessThan(9112592, $response->decay);
|
||||
}
|
||||
|
||||
public function testAjaxGetBalanceInvalidSession()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'email_checked' => 1,
|
||||
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
|
||||
]
|
||||
]);
|
||||
//echo "balance: $balance";
|
||||
$this->getAndParse('/state-balances/ajaxGetBalance/' . 1211,
|
||||
['state' => 'not found', 'msg' => 'invalid session']
|
||||
);
|
||||
}
|
||||
|
||||
public function testAjaxGetBalanceInvalidSessionId()
|
||||
{
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'email_checked' => 1,
|
||||
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
|
||||
]
|
||||
]);
|
||||
//echo "balance: $balance";
|
||||
$this->getAndParse('/state-balances/ajaxGetBalance' ,
|
||||
['state' => 'error', 'msg' => 'invalid session id']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ajaxListTransactions method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAjaxListTransactions()
|
||||
{
|
||||
//ajaxListTransactions
|
||||
$session_id = rand();
|
||||
$this->session([
|
||||
'session_id' => $session_id,
|
||||
'Transaction' => ['pending' => 0, 'executing' => 0],
|
||||
'StateUser' => [
|
||||
'id' => 1,
|
||||
'first_name' => 'Dario',
|
||||
'last_name' => 'Frodo',
|
||||
'email_checked' => 1,
|
||||
'email' => 'fördertest@gradido.org',
|
||||
'public_hex' => '94ae135b93cd9f33752b4e55c41903a3faa13a75bb90bfd411ea1d4a1a5e711f'
|
||||
]
|
||||
]);
|
||||
//echo "balance: $balance";
|
||||
$this->getAndParse('/state-balances/ajaxListTransactions/' . $session_id,
|
||||
[
|
||||
'state' => 'success', 'transactions' => [[
|
||||
'name' => 'Dario Frodo',
|
||||
'email'=> 'dariofrodo@gmx.de',
|
||||
'type'=> '',
|
||||
'transaction_id' => 4,
|
||||
'date' => '2021-02-19T13:27:14+00:00',
|
||||
'balance' => 150000001,
|
||||
'memo' => ''
|
||||
]],
|
||||
'transactionExecutingCount' => 0,
|
||||
'count' => 1,
|
||||
'gdtSum' => 0,
|
||||
'timeUsed' => 0.03168010711669922
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test overviewGdt method
|
||||
|
||||
@ -1,174 +0,0 @@
|
||||
<?php
|
||||
namespace App\Test\TestCase\Controller;
|
||||
|
||||
use App\Controller\JsonRequestHandlerController;
|
||||
use Cake\TestSuite\IntegrationTestTrait;
|
||||
use Cake\TestSuite\TestCase;
|
||||
|
||||
/**
|
||||
* App\Controller\TransactionJsonRequestHandlerController Test Case
|
||||
*
|
||||
* @uses \App\Controller\TransactionJsonRequestHandlerController
|
||||
*/
|
||||
class TransactionJsonRequestHandlerControllerTest extends TestCase
|
||||
{
|
||||
use IntegrationTestTrait;
|
||||
|
||||
/**
|
||||
* Fixtures
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fixtures = [
|
||||
'app.TransactionCreations',
|
||||
'app.Transactions',
|
||||
'app.StateUsers',
|
||||
'app.StateErrors',
|
||||
'app.TransactionSignatures',
|
||||
'app.TransactionSendCoins',
|
||||
'app.StateBalances',
|
||||
'app.TransactionTypes'
|
||||
];
|
||||
|
||||
public $transactions = [
|
||||
'validCreation' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQJ8wF12eZo3hcMAlAKKJ9WLT-zuSkNmGh7D98UEqH4KoIysnCkXqEya9EBZl9o11_nJ8xmm_nOevuVjR-GfLMQ8qSQoOSGFsbG8gV2VsdCAxMjMSBgiZm4ruBUovCicKIJSuE1uTzZ8zdStOVcQZA6P6oTp1u5C_1BHqHUoaXnEfEKDakwEQtYntlgo',
|
||||
'validCreation900' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQNVZ8Ae3Zbg3G0wZ840fzKan6N4KtTcSe0KYi17kQwFmsl18oFxXv8_s6j1xXFrIKjy1_1Olq0a7xYLErDMkjwYqORIGCNb5iu4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgNHKCBC1ie2WCg',
|
||||
'validCreation1200' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQEEey5QMAdldoOTP_jTETHgOQriGsixEY0cziQeRfT_J5YtbI_A6AizEYD-JcxmRmXzv1xjjTgsV39Y32ta2CQkqORIGCIeGi-4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgOy4CxC1ie2WCg',
|
||||
'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3',
|
||||
'validTransfer' => 'GmYKZAoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0SQDddHyKzAX3LBV0PuDiPc6lxkUipss5tyuLRpMtFJQnT30tsbYIkA1FXimjMKOoiuLswf4OLLV3bAIYehW-b9AgqYQoFSGFsbG8SBgiJlaPvBUJQCiYKIIGQvaWF7l8dn799BugeaewY4TN2EEz_VLdFfrfT73ENEICfSRImCiDtdleSLxhUgEbMW9DpqIwsykFj3-z_enKEOuGnXrmW8xCAn0k',
|
||||
'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ=='
|
||||
];
|
||||
|
||||
/*public function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
*/
|
||||
public function testWrongMethod()
|
||||
{
|
||||
$this->configRequest([
|
||||
'headers' => ['Accept' => 'application/json']
|
||||
]);
|
||||
$this->get('/TransactionJsonRequestHandler');
|
||||
$this->assertResponseOk();
|
||||
|
||||
$expected = json_encode(['state' => 'error', 'msg' => 'no post']);
|
||||
$this->assertEquals($expected, (string)$this->_response->getBody());
|
||||
}
|
||||
|
||||
public function testInvalidJson()
|
||||
{
|
||||
$this->configRequest([
|
||||
'headers' => ['Accept' => 'application/json']
|
||||
]);
|
||||
$this->post('/TransactionJsonRequestHandler', '{This isn\'t valid json}');
|
||||
$this->assertResponseOk();
|
||||
|
||||
$expected = json_encode(['state' => 'error', 'msg' => 'parameter error']);
|
||||
$this->assertEquals($expected, (string)$this->_response->getBody());
|
||||
}
|
||||
|
||||
public function testNotSetTransaction()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction'],
|
||||
['state' => 'error', 'msg' => 'parameter error']
|
||||
);
|
||||
}
|
||||
public function testNotSetMethod()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['transaction' => $this->transactions['validCreation']],
|
||||
['state' => 'error', 'msg' => 'parameter error']
|
||||
);
|
||||
}
|
||||
|
||||
public function testUnknownMethod()
|
||||
{
|
||||
//$this->post('/TransactionJsonRequestHandler', ['method' => 'putTransaction', 'transaction' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3/cHHaWchkUhWiGhQjB23xCg2pMBELWJ7ZYK']);
|
||||
$this->postAndParse(
|
||||
['method' => 'foobar', 'transaction' => $this->transactions['validCreation']],
|
||||
['state' => 'error', 'msg' => 'unknown method', 'details' => 'foobar']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function testInvalidEncodedTransaction() {
|
||||
//"msg":"error parsing transaction","details":[{"Transaction":"base64 decode error"}]
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['notBase64']],
|
||||
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
|
||||
['Transaction' => 'invalid base64 string']
|
||||
]]
|
||||
);
|
||||
}
|
||||
|
||||
public function testInvalidTransaction() {
|
||||
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => base64_encode('Hallo Miau Welt')],
|
||||
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
|
||||
['Transaction' => 'Error occurred during parsing: Unexpected wire type.']
|
||||
]]
|
||||
);
|
||||
}
|
||||
|
||||
public function testToLargeCreationSum()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation900']],
|
||||
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
|
||||
);
|
||||
}
|
||||
|
||||
public function testToLargeCreation()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation1200']],
|
||||
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
|
||||
);
|
||||
}
|
||||
|
||||
public function testValidTransfer()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']],
|
||||
['state' => 'success']
|
||||
);
|
||||
}
|
||||
|
||||
/*public function testMissingPreviousTransaction()
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
public function testValidTransaction()
|
||||
{
|
||||
$this->postAndParse(
|
||||
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
|
||||
['state' => 'success']
|
||||
);
|
||||
}
|
||||
|
||||
private function postAndParse($params, $expected)
|
||||
{
|
||||
|
||||
$this->configRequest([
|
||||
'headers' => ['Accept' => 'application/json']
|
||||
]);
|
||||
|
||||
$this->disableErrorHandlerMiddleware();
|
||||
$this->post('/TransactionJsonRequestHandler', json_encode($params));
|
||||
|
||||
// Check that the response was a 200
|
||||
$this->assertResponseOk();
|
||||
|
||||
$responseBodyString = (string)$this->_response->getBody();
|
||||
$json = json_decode($responseBodyString);
|
||||
$this->assertNotFalse($json);
|
||||
|
||||
if(is_array($expected)) {
|
||||
$expected = json_encode($expected);
|
||||
}
|
||||
$this->assertEquals($expected, $responseBodyString);
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
namespace App\Test\TestCase\Model\Entity;
|
||||
|
||||
use App\Model\Entity\Table;
|
||||
use Cake\TestSuite\TestCase;
|
||||
|
||||
/**
|
||||
* App\Model\Entity\Table Test Case
|
||||
*/
|
||||
class TableTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test subject
|
||||
*
|
||||
* @var \App\Model\Entity\Table
|
||||
*/
|
||||
public $Table;
|
||||
|
||||
/**
|
||||
* setUp method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->Table = new Table();
|
||||
}
|
||||
|
||||
/**
|
||||
* tearDown method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
unset($this->Table);
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test initial setup
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInitialization()
|
||||
{
|
||||
$this->markTestIncomplete('Not implemented yet.');
|
||||
}
|
||||
}
|
||||
@ -30,84 +30,12 @@ class TransactionCreationTest extends TestCase
|
||||
parent::setUp();
|
||||
|
||||
}
|
||||
|
||||
public function testHashingFunction()
|
||||
public function testDummy()
|
||||
{
|
||||
$pairs = [
|
||||
"a" => 97,
|
||||
"b" => 98,
|
||||
"c" => 99,
|
||||
"d" => 100,
|
||||
"aa" => 12513,
|
||||
"ab" => 12514,
|
||||
"@" => 64,
|
||||
".d" => 5988,
|
||||
"gmx" => 1701624,
|
||||
"@gmx" => 135919352,
|
||||
"@gmx.de" => 3742152099,
|
||||
"***REMOVED***" => 2928827813,
|
||||
"***REMOVED***" => 1899591683,
|
||||
"***REMOVED***" => 2089074830,
|
||||
"maximilian.muster@gradido.net" => 793144931,
|
||||
"coin-info5@gradido.net" => 1829129963,
|
||||
"coin-info6@gradido.net" => 1830178539,
|
||||
"coin-info8@gradido.net" => 1832275691,
|
||||
"coin-info9@gradido.net" => 1833324267,
|
||||
"coin-info10@gradido.net" => 3877298078,
|
||||
"coin-info11@gradido.net" => 3878346654,
|
||||
"coin-info12@gradido.net" => 3879395230,
|
||||
"***REMOVED***" => 2089074830,
|
||||
"***REMOVED***" => 3996757473,
|
||||
"***REMOVED***" => 3788634614,
|
||||
"***REMOVED***" => 807797884,
|
||||
"***REMOVED***" => 1640973721,
|
||||
"***REMOVED***" => 2025729173,
|
||||
"***REMOVED***" => 1961122507,
|
||||
"***REMOVED***" => 362466358,
|
||||
"***REMOVED***" => 3796728871,
|
||||
"***REMOVED***" => 807797884,
|
||||
"***REMOVED***" => 3794905967,
|
||||
"***REMOVED***" => 3077694284,
|
||||
"***REMOVED***" => 3246159770,
|
||||
"***REMOVED***" => 3123402690,
|
||||
"testneu-11-12-3@gradido.net" => 4092403827,
|
||||
"***REMOVED***" => 3151414199,
|
||||
"***REMOVED***" => 3526188273,
|
||||
"***REMOVED***" => 966804823,
|
||||
"***REMOVED***" => 1309273258,
|
||||
"***REMOVED***" => 995978784,
|
||||
"***REMOVED***" => 310113324,
|
||||
"***REMOVED***" => 1309273258,
|
||||
"***REMOVED***" => 530108573,
|
||||
"***REMOVED***" => 1734855679,
|
||||
"***REMOVED***" => 767779182,
|
||||
"***REMOVED***" => 2247491519,
|
||||
"***REMOVED***" => 3248626267,
|
||||
"***REMOVED***" => 3516649930,
|
||||
"***REMOVED***" => 231214190,
|
||||
"***REMOVED***" => 4247461928,
|
||||
"***REMOVED***" => 324829839,
|
||||
"***REMOVED***" => 3046147747,
|
||||
"***REMOVED***" => 3207307415,
|
||||
"***REMOVED***" => 728893500,
|
||||
"***REMOVED***" => 3905254663,
|
||||
"***REMOVED***" => 3207307415,
|
||||
"***REMOVED***" => 1155733239,
|
||||
"***REMOVED***" => 2013046423,
|
||||
"***REMOVED***" => 4033835283,
|
||||
"***REMOVED***" => 1945541625,
|
||||
"***REMOVED***" => 2310715309,
|
||||
"***REMOVED***" => 1221362064,
|
||||
"***REMOVED***" => 4161339877
|
||||
];
|
||||
foreach($pairs as $email => $cpp_hash) {
|
||||
$php_hash = TransactionCreation::DRMakeStringHash($email);
|
||||
// assertEquals(mixed $expected, mixed $actual[, string $message = ''])
|
||||
if($php_hash != $cpp_hash) {
|
||||
$this->assertEquals($cpp_hash, $php_hash, "hashes for $email don't match");
|
||||
}
|
||||
}
|
||||
$this->assertEquals(true, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -214,9 +214,8 @@ return [
|
||||
'timeout' => 30,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
'client' => null,
|
||||
'tls' => null,
|
||||
'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
|
||||
'className' => 'Smtp',
|
||||
'tls' => true
|
||||
],
|
||||
],
|
||||
|
||||
@ -304,11 +303,11 @@ return [
|
||||
'className' => Connection::class,
|
||||
'driver' => Mysql::class,
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'host' => 'mariadb',
|
||||
//'port' => 'non_standard_port_number',
|
||||
'username' => 'my_app',
|
||||
'password' => 'secret',
|
||||
'database' => 'test_myapp',
|
||||
'username' => 'root',
|
||||
'password' => '',
|
||||
'database' => 'gradido_community_test',
|
||||
//'encoding' => 'utf8mb4',
|
||||
'timezone' => 'UTC',
|
||||
'cacheMetadata' => true,
|
||||
|
||||
57
configs/login_server/grd_login_test.properties
Normal file
57
configs/login_server/grd_login_test.properties
Normal file
@ -0,0 +1,57 @@
|
||||
HTTPServer.port = 1200
|
||||
JSONServer.port = 1201
|
||||
Gradido.group_id = 1
|
||||
|
||||
crypto.server_admin_public = f909a866baec97c5460b8d7a93b72d3d4d20cc45d9f15d78bd83944eb9286b7f
|
||||
crypto.server_key = a51ef8ac7ef1abf162fb7a65261acd7a
|
||||
# TODO auto-generate in docker build step
|
||||
crypto.app_secret = 21ffbbc616fe
|
||||
|
||||
# Server admin Passphrase
|
||||
# nerve execute merit pool talk hockey basic win cargo spin disagree ethics swear price purchase say clutch decrease slow half forest reform cheese able
|
||||
#
|
||||
|
||||
phpServer.url = http://localhost/
|
||||
phpServer.host = nginx
|
||||
|
||||
loginServer.path = http://localhost/account
|
||||
loginServer.default_locale = de
|
||||
loginServer.db.host = mariadb
|
||||
loginServer.db.name = gradido_login_test
|
||||
loginServer.db.user = root
|
||||
loginServer.db.password =
|
||||
loginServer.db.port = 3306
|
||||
|
||||
frontend.checkEmailPath = http://localhost/reset
|
||||
|
||||
email.disable = true
|
||||
|
||||
#email.username =
|
||||
#email.sender =
|
||||
#email.admin_receiver =
|
||||
#email.password =
|
||||
#email.smtp.url =
|
||||
#email.smtp.port =
|
||||
|
||||
# binary is default, for debugging also json is possible
|
||||
#hedera.consensus.message_format = json
|
||||
# TESTNET or MAINNET, TESTNET is default
|
||||
hedera.nettype = TESTNET
|
||||
|
||||
# server setup types: test, staging or production
|
||||
ServerSetupType=test
|
||||
dev.default_group = docker
|
||||
|
||||
|
||||
# Session timeout in minutes
|
||||
#
|
||||
session.timeout = 15
|
||||
|
||||
# Disabling security features for faster develop and testing
|
||||
unsecure.allow_passwort_via_json_request = 1
|
||||
unsecure.allow_auto_sign_transactions = 1
|
||||
unsecure.allow_cors_all = 1
|
||||
# default disable, passwords must contain a number, a lower character, a high character, special character, and be at least 8 characters long
|
||||
|
||||
unsecure.allow_all_passwords = 1
|
||||
|
||||
@ -38,7 +38,7 @@ services:
|
||||
- ./login_server/dependencies:/code/dependencies
|
||||
- ./login_server/scripts:/code/scripts
|
||||
- ./configs/login_server:/etc/grd_login
|
||||
- login_build_3:/code/build
|
||||
- login_build_3.1:/code/build
|
||||
|
||||
|
||||
#########################################################
|
||||
@ -47,11 +47,8 @@ services:
|
||||
community-server:
|
||||
build:
|
||||
context: .
|
||||
target: community_server
|
||||
dockerfile: ./community_server/Dockerfile
|
||||
environment:
|
||||
- DB_PASSWORD=''
|
||||
- DB_USER='root'
|
||||
- DB_DATABASE='gradido_community'
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
@ -103,4 +100,4 @@ services:
|
||||
|
||||
volumes:
|
||||
frontend_node_modules:
|
||||
login_build_3:
|
||||
login_build_3.1:
|
||||
|
||||
99
docker-compose.test.yml
Normal file
99
docker-compose.test.yml
Normal file
@ -0,0 +1,99 @@
|
||||
version: "3.4"
|
||||
|
||||
services:
|
||||
|
||||
#########################################################
|
||||
## MARIADB ##############################################
|
||||
#########################################################
|
||||
mariadb:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./mariadb/Dockerfile
|
||||
target: mariadb_server_test
|
||||
environment:
|
||||
- MARIADB_ALLOW_EMPTY_PASSWORD=1
|
||||
- MARIADB_USER=root
|
||||
networks:
|
||||
- internal-net
|
||||
ports:
|
||||
- 3306:3306
|
||||
volumes:
|
||||
- db_test_vol:/var/lib/mysql
|
||||
|
||||
#########################################################
|
||||
## LOGIN SERVER #########################################
|
||||
#########################################################
|
||||
login-server:
|
||||
build:
|
||||
context: ./login_server/
|
||||
target: test
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
cap_add:
|
||||
- SYS_PTRACE
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
- internal-net
|
||||
volumes:
|
||||
- ./logs:/var/log/grd_login
|
||||
- ./login_server/src:/code/src
|
||||
- ./configs/login_server:/etc/grd_login
|
||||
- login_build_cov:/code/build_cov
|
||||
- ./coverage/login:/code/build_cov/coverage_html
|
||||
|
||||
#########################################################
|
||||
## COMMUNITY SERVER (cakephp with php-fpm) ##############
|
||||
#########################################################
|
||||
community-server:
|
||||
build:
|
||||
context: .
|
||||
target: test
|
||||
dockerfile: ./community_server/Dockerfile
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
- internal-net
|
||||
volumes:
|
||||
- ./community_server/config/php-fpm/php-ini-overrides.ini:/etc/php/7.4/fpm/conf.d/99-overrides.ini
|
||||
- ./community_server/src:/var/www/cakephp/src
|
||||
- ./coverage/community:/var/www/cakephp/webroot/coverage
|
||||
|
||||
|
||||
#########################################################
|
||||
## PHPMYADMIN ###########################################
|
||||
#########################################################
|
||||
phpmyadmin:
|
||||
image: phpmyadmin
|
||||
environment:
|
||||
- PMA_ARBITRARY=1
|
||||
#restart: always
|
||||
ports:
|
||||
- 8074:80
|
||||
networks:
|
||||
- internal-net
|
||||
- external-net
|
||||
volumes:
|
||||
- /sessions
|
||||
|
||||
#########################################################
|
||||
## skeema for updating dbs if changes happend ###########
|
||||
#########################################################
|
||||
skeema:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./skeema/Dockerfile
|
||||
target: skeema_run
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
- internal-net
|
||||
|
||||
networks:
|
||||
external-net:
|
||||
internal-net:
|
||||
internal: true
|
||||
|
||||
volumes:
|
||||
db_test_vol:
|
||||
login_build_cov:
|
||||
@ -38,7 +38,7 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./mariadb/Dockerfile
|
||||
target: mariadb_server
|
||||
target: mariadb_server_test
|
||||
environment:
|
||||
- MARIADB_ALLOW_EMPTY_PASSWORD=1
|
||||
- MARIADB_USER=root
|
||||
@ -47,7 +47,7 @@ services:
|
||||
ports:
|
||||
- 3306:3306
|
||||
volumes:
|
||||
- db_vol:/var/lib/mysql
|
||||
- db_vol:/var/lib/mysql
|
||||
|
||||
#########################################################
|
||||
## LOGIN SERVER #########################################
|
||||
@ -80,6 +80,7 @@ services:
|
||||
depends_on:
|
||||
- community-server
|
||||
- login-server
|
||||
- frontend
|
||||
ports:
|
||||
- 80:80
|
||||
|
||||
@ -89,6 +90,7 @@ services:
|
||||
community-server:
|
||||
build:
|
||||
context: .
|
||||
target: community_server
|
||||
dockerfile: ./community_server/Dockerfile
|
||||
environment:
|
||||
- DB_PASSWORD=''
|
||||
|
||||
@ -89,6 +89,56 @@ In case of success returns:
|
||||
nginx was wrong configured.
|
||||
- `session_id`: can be also negative
|
||||
|
||||
## Check username
|
||||
### Request
|
||||
`GET http://localhost/login_api/checkUsername?username=<username>&group_id=<group_id>`
|
||||
|
||||
`POST http://localhost/login_api/checkUsername`
|
||||
with
|
||||
```json
|
||||
{
|
||||
"username": "Maxilein",
|
||||
"group_id": 1,
|
||||
"group_alias": "gdd1"
|
||||
}
|
||||
```
|
||||
|
||||
group_id or group_alias, one of both is enough.
|
||||
group_id is better, because one db request less
|
||||
|
||||
### Response
|
||||
|
||||
If username is not already taken
|
||||
```json
|
||||
{
|
||||
"state":"success"
|
||||
}
|
||||
```
|
||||
|
||||
If username is already taken
|
||||
```json
|
||||
{
|
||||
"state":"warning",
|
||||
"msg":"username already in use"
|
||||
}
|
||||
```
|
||||
|
||||
If only group_alias was given and group with that alias was found in db
|
||||
```json
|
||||
{
|
||||
"state":"success",
|
||||
"group_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
If group_id or group_alias unknown
|
||||
```json
|
||||
{
|
||||
"state":"error",
|
||||
"msg": "unknown group"
|
||||
}
|
||||
```
|
||||
|
||||
## Create user
|
||||
Register a new User
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
"nouislider": "^12.1.0",
|
||||
"particles-bg-vue": "1.2.3",
|
||||
"perfect-scrollbar": "^1.3.0",
|
||||
"portal-vue": "^2.1.7",
|
||||
"prettier": "^2.2.1",
|
||||
"qrcode": "^1.4.4",
|
||||
"quill": "^1.3.6",
|
||||
@ -58,12 +59,14 @@
|
||||
"sweetalert2": "^9.5.4",
|
||||
"vee-validate": "^3.4.5",
|
||||
"vue": "^2.6.11",
|
||||
"vue-bootstrap-toasts": "^1.0.7",
|
||||
"vue-bootstrap-typeahead": "^0.2.6",
|
||||
"vue-chartjs": "^3.5.0",
|
||||
"vue-cli-plugin-i18n": "^1.0.1",
|
||||
"vue-clickaway": "^2.2.2",
|
||||
"vue-clipboard2": "^0.3.0",
|
||||
"vue-flatpickr-component": "^8.1.2",
|
||||
"vue-focus": "^2.1.0",
|
||||
"vue-good-table": "^2.21.3",
|
||||
"vue-i18n": "^8.22.4",
|
||||
"vue-jest": "^3.0.7",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
<div class="">
|
||||
<particles-bg type="custom" :config="config" :bg="true" />
|
||||
<component :is="$route.meta.requiresAuth ? 'DashboardLayout' : 'AuthLayoutGDD'" />
|
||||
<Toasts></Toasts>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -35,7 +35,7 @@ const communityAPI = {
|
||||
balance: async (sessionId) => {
|
||||
return apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId)
|
||||
},
|
||||
transactions: async (sessionId, firstPage = 1, items = 1000, order = 'DESC') => {
|
||||
transactions: async (sessionId, firstPage = 1, items = 5, order = 'DESC') => {
|
||||
return apiGet(
|
||||
`${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${sessionId}`,
|
||||
)
|
||||
|
||||
@ -78,6 +78,26 @@ const loginAPI = {
|
||||
CONFIG.LOGIN_API_URL + 'loginViaEmailVerificationCode?emailVerificationCode=' + optin,
|
||||
)
|
||||
},
|
||||
getUserInfos: async (sessionId, email) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email: email,
|
||||
ask: ['user.first_name', 'user.last_name'],
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'getUserInfos', payload)
|
||||
},
|
||||
updateUserInfos: async (sessionId, email, data) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
update: {
|
||||
'User.first_name': data.firstName,
|
||||
'User.last_name': data.lastName,
|
||||
'User.description': data.description,
|
||||
},
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
changePassword: async (sessionId, email, password) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
@ -88,6 +108,27 @@ const loginAPI = {
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
changePasswordProfile: async (sessionId, email, password, passwordNew) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
update: {
|
||||
'User.password': password,
|
||||
'User.passwordNew': passwordNew,
|
||||
},
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
changeUsernameProfile: async (sessionId, email, username) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
update: {
|
||||
'User.username': username,
|
||||
},
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
updateLanguage: async (sessionId, email, language) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
|
||||
@ -23,38 +23,95 @@
|
||||
|
||||
// Bootstrap (4.1.3) components
|
||||
|
||||
@import "~bootstrap/scss/root";
|
||||
@import "~bootstrap/scss/reboot";
|
||||
@import "~bootstrap/scss/type";
|
||||
@import "~bootstrap/scss/images";
|
||||
@import "~bootstrap/scss/code";
|
||||
@import "~bootstrap/scss/grid";
|
||||
@import "~bootstrap/scss/tables";
|
||||
@import "~bootstrap/scss/forms";
|
||||
@import "~bootstrap/scss/buttons";
|
||||
@import "~bootstrap/scss/transitions";
|
||||
@import "~bootstrap/scss/dropdown";
|
||||
@import "~bootstrap/scss/alert";
|
||||
@import "~bootstrap/scss/badge";
|
||||
@import "~bootstrap/scss/breadcrumb";
|
||||
@import "~bootstrap/scss/button-group";
|
||||
@import "~bootstrap/scss/input-group";
|
||||
@import "~bootstrap/scss/buttons";
|
||||
@import "~bootstrap/scss/card";
|
||||
@import "~bootstrap/scss/carousel";
|
||||
@import "~bootstrap/scss/close";
|
||||
@import "~bootstrap/scss/code";
|
||||
@import "~bootstrap/scss/custom-forms";
|
||||
@import "~bootstrap/scss/dropdown";
|
||||
@import "~bootstrap/scss/forms";
|
||||
@import "~bootstrap/scss/grid";
|
||||
@import "~bootstrap/scss/images";
|
||||
@import "~bootstrap/scss/input-group";
|
||||
@import "~bootstrap/scss/jumbotron";
|
||||
@import "~bootstrap/scss/list-group";
|
||||
@import "~bootstrap/scss/media";
|
||||
@import "~bootstrap/scss/modal";
|
||||
@import "~bootstrap/scss/nav";
|
||||
@import "~bootstrap/scss/navbar";
|
||||
@import "~bootstrap/scss/card";
|
||||
@import "~bootstrap/scss/breadcrumb";
|
||||
@import "~bootstrap/scss/pagination";
|
||||
@import "~bootstrap/scss/badge";
|
||||
@import "~bootstrap/scss/jumbotron";
|
||||
@import "~bootstrap/scss/alert";
|
||||
@import "~bootstrap/scss/progress";
|
||||
@import "~bootstrap/scss/media";
|
||||
@import "~bootstrap/scss/list-group";
|
||||
@import "~bootstrap/scss/close";
|
||||
@import "~bootstrap/scss/modal";
|
||||
@import "~bootstrap/scss/tooltip";
|
||||
@import "~bootstrap/scss/popover";
|
||||
@import "~bootstrap/scss/carousel";
|
||||
@import "~bootstrap/scss/utilities";
|
||||
@import "~bootstrap/scss/print";
|
||||
@import "~bootstrap/scss/progress";
|
||||
@import "~bootstrap/scss/reboot";
|
||||
@import "~bootstrap/scss/root";
|
||||
@import "~bootstrap/scss/tables";
|
||||
@import "~bootstrap/scss/toasts";
|
||||
@import "~bootstrap/scss/tooltip";
|
||||
@import "~bootstrap/scss/transitions";
|
||||
@import "~bootstrap/scss/type";
|
||||
@import "~bootstrap/scss/utilities";
|
||||
@import "~bootstrap/scss/variables";
|
||||
|
||||
// Utilities
|
||||
|
||||
@import "~bootstrap/scss/utilities/align";
|
||||
@import "~bootstrap/scss/utilities/background";
|
||||
@import "~bootstrap/scss/utilities/borders";
|
||||
@import "~bootstrap/scss/utilities/clearfix";
|
||||
@import "~bootstrap/scss/utilities/display";
|
||||
@import "~bootstrap/scss/utilities/embed";
|
||||
@import "~bootstrap/scss/utilities/flex";
|
||||
@import "~bootstrap/scss/utilities/float";
|
||||
@import "~bootstrap/scss/utilities/overflow";
|
||||
@import "~bootstrap/scss/utilities/position";
|
||||
@import "~bootstrap/scss/utilities/screenreaders";
|
||||
@import "~bootstrap/scss/utilities/shadows";
|
||||
@import "~bootstrap/scss/utilities/sizing";
|
||||
@import "~bootstrap/scss/utilities/spacing";
|
||||
@import "~bootstrap/scss/utilities/stretched-link";
|
||||
@import "~bootstrap/scss/utilities/text";
|
||||
@import "~bootstrap/scss/utilities/visibility";
|
||||
|
||||
|
||||
// Mixins
|
||||
|
||||
@import "~bootstrap/scss/mixins/alert";
|
||||
@import "~bootstrap/scss/mixins/badge";
|
||||
@import "~bootstrap/scss/mixins/border-radius";
|
||||
@import "~bootstrap/scss/mixins/box-shadow";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
@import "~bootstrap/scss/mixins/buttons";
|
||||
@import "~bootstrap/scss/mixins/caret";
|
||||
@import "~bootstrap/scss/mixins/clearfix";
|
||||
@import "~bootstrap/scss/mixins/deprecate";
|
||||
@import "~bootstrap/scss/mixins/float";
|
||||
@import "~bootstrap/scss/mixins/forms";
|
||||
@import "~bootstrap/scss/mixins/gradients";
|
||||
@import "~bootstrap/scss/mixins/grid-framework";
|
||||
@import "~bootstrap/scss/mixins/grid";
|
||||
@import "~bootstrap/scss/mixins/hover";
|
||||
@import "~bootstrap/scss/mixins/image";
|
||||
@import "~bootstrap/scss/mixins/list-group";
|
||||
@import "~bootstrap/scss/mixins/lists";
|
||||
@import "~bootstrap/scss/mixins/nav-divider";
|
||||
@import "~bootstrap/scss/mixins/pagination";
|
||||
@import "~bootstrap/scss/mixins/reset-text";
|
||||
@import "~bootstrap/scss/mixins/resize";
|
||||
@import "~bootstrap/scss/mixins/screen-reader";
|
||||
@import "~bootstrap/scss/mixins/size";
|
||||
@import "~bootstrap/scss/mixins/table-row";
|
||||
@import "~bootstrap/scss/mixins/text-emphasis";
|
||||
@import "~bootstrap/scss/mixins/text-hide";
|
||||
@import "~bootstrap/scss/mixins/text-truncate";
|
||||
@import "~bootstrap/scss/mixins/transition";
|
||||
@import "~bootstrap/scss/mixins/visibility";
|
||||
|
||||
|
||||
// Argon utilities and components
|
||||
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
//
|
||||
// Circle badge
|
||||
//
|
||||
|
||||
|
||||
// General styles
|
||||
|
||||
.badge-circle {
|
||||
text-align: center;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
font-size: .875rem;
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
//
|
||||
// Dot badge
|
||||
//
|
||||
|
||||
|
||||
// General styles
|
||||
|
||||
.badge-dot {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
background: transparent;
|
||||
font-weight: $font-weight-normal;
|
||||
font-size: $font-size-sm;
|
||||
text-transform: none;
|
||||
|
||||
strong {
|
||||
color: $gray-800;
|
||||
}
|
||||
|
||||
i {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: .375rem;
|
||||
height: .375rem;
|
||||
border-radius: 50%;
|
||||
margin-right: .375rem;
|
||||
}
|
||||
|
||||
&.badge-md {
|
||||
i {
|
||||
width: .5rem;
|
||||
height: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.badge-lg {
|
||||
i {
|
||||
width: .625rem;
|
||||
height: .625rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
//
|
||||
// Badge
|
||||
//
|
||||
|
||||
|
||||
// General styles
|
||||
|
||||
.badge {
|
||||
text-transform: $badge-text-transfom;
|
||||
|
||||
a {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Size variations
|
||||
|
||||
.badge-md {
|
||||
padding: .65em 1em;
|
||||
}
|
||||
|
||||
.badge-lg {
|
||||
padding: .85em 1.375em;
|
||||
}
|
||||
|
||||
|
||||
// Multiple inline badges
|
||||
|
||||
.badge-inline {
|
||||
margin-right: .625rem;
|
||||
|
||||
+ span {
|
||||
top: 2px;
|
||||
position: relative;
|
||||
|
||||
> a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Badge spacing inside a btn with some text
|
||||
|
||||
.btn {
|
||||
.badge {
|
||||
&:not(:first-child) {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
@import "custom/alert";
|
||||
@import "custom/avatar";
|
||||
@import "custom/badge";
|
||||
@import "custom/buttons";
|
||||
@import "custom/card";
|
||||
@import "custom/chart";
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<b-badge :variant="type" :pill="rounded" :size="size" :class="{ 'badge-circle': circle }">
|
||||
<slot>
|
||||
<i v-if="icon" :class="icon"></i>
|
||||
</slot>
|
||||
</b-badge>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'badge',
|
||||
props: {
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'span',
|
||||
description: 'Html tag to use for the badge.',
|
||||
},
|
||||
rounded: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether badge is of pill type',
|
||||
},
|
||||
circle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether badge is circle',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Icon name. Will be overwritten by slot if slot is used',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
description: 'Badge type (primary|info|danger|default|warning|success)',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
description: 'Badge size (md, lg)',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<fade-transition>
|
||||
<b-alert
|
||||
v-model="visible"
|
||||
:variant="type"
|
||||
:class="[{ 'alert-dismissible': dismissible }]"
|
||||
role="alert"
|
||||
>
|
||||
<slot v-if="!dismissible"></slot>
|
||||
<template v-else>
|
||||
<template v-if="icon || $slots.icon">
|
||||
<slot name="icon">
|
||||
<span class="alert-icon" data-notify="icon">
|
||||
<i :class="icon"></i>
|
||||
</span>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<span class="alert-text"><slot></slot></span>
|
||||
|
||||
<slot name="dismiss-icon">
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="alert"
|
||||
aria-label="Close"
|
||||
@click="dismissAlert"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</slot>
|
||||
</template>
|
||||
</b-alert>
|
||||
</fade-transition>
|
||||
</template>
|
||||
<script>
|
||||
import { FadeTransition } from 'vue2-transitions'
|
||||
|
||||
export default {
|
||||
name: 'base-alert',
|
||||
components: {
|
||||
FadeTransition,
|
||||
},
|
||||
created() {
|
||||
// console.log('base-alert gesetzt in =>', this.$route.path)
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
description: 'Alert type',
|
||||
},
|
||||
dismissible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether alert is dismissible (closeable)',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Alert icon to display',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dismissAlert() {
|
||||
this.visible = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<b-button
|
||||
:type="nativeType"
|
||||
:disabled="disabled || loading"
|
||||
@click="handleClick"
|
||||
class="base-button"
|
||||
:variant="!outline ? type : `outline-${type}`"
|
||||
:size="size"
|
||||
:block="block"
|
||||
:class="[
|
||||
{ 'rounded-circle': round },
|
||||
{ 'btn-wd': wide },
|
||||
{ 'btn-icon btn-fab': icon },
|
||||
{ 'btn-link': link },
|
||||
{ disabled: disabled },
|
||||
]"
|
||||
>
|
||||
<slot name="loading">
|
||||
<i v-if="loading" class="fas fa-spinner fa-spin"></i>
|
||||
</slot>
|
||||
<slot></slot>
|
||||
</b-button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-button',
|
||||
props: {
|
||||
round: Boolean,
|
||||
icon: Boolean,
|
||||
block: Boolean,
|
||||
loading: Boolean,
|
||||
wide: Boolean,
|
||||
disabled: Boolean,
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
description: 'Button type (primary|secondary|danger etc)',
|
||||
},
|
||||
nativeType: {
|
||||
type: String,
|
||||
default: 'button',
|
||||
description: 'Button native type (e.g button, input etc)',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Button size (sm|lg)',
|
||||
},
|
||||
outline: {
|
||||
type: Boolean,
|
||||
description: 'Whether button is outlined (only border has color)',
|
||||
},
|
||||
link: {
|
||||
type: Boolean,
|
||||
description: 'Whether button is a link (no borders or background)',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick(evt) {
|
||||
this.$emit('click', evt)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.base-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
i {
|
||||
padding: 0 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,97 +0,0 @@
|
||||
<template>
|
||||
<component
|
||||
:is="tag"
|
||||
:class="[{ show: isOpen }, `drop${direction}`]"
|
||||
@click="toggleDropDown"
|
||||
v-click-outside="closeDropDown"
|
||||
>
|
||||
<slot name="title-container" :is-open="isOpen">
|
||||
<component
|
||||
:is="titleTag"
|
||||
class="btn-rotate"
|
||||
:class="[{ 'dropdown-toggle': hasToggle }, titleClasses]"
|
||||
:aria-expanded="isOpen"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<slot name="title" :is-open="isOpen">
|
||||
<i :class="icon"></i>
|
||||
{{ title }}
|
||||
</slot>
|
||||
</component>
|
||||
</slot>
|
||||
<ul
|
||||
class="dropdown-menu"
|
||||
:class="[{ show: isOpen }, { 'dropdown-menu-right': menuOnRight }, menuClasses]"
|
||||
>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</component>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-dropdown',
|
||||
props: {
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'div',
|
||||
description: 'Dropdown html tag (e.g div, ul etc)',
|
||||
},
|
||||
titleTag: {
|
||||
type: String,
|
||||
default: 'button',
|
||||
description: 'Dropdown title (toggle) html tag',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
description: 'Dropdown title',
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'down', // up | down
|
||||
description: 'Dropdown menu direction (up|down)',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
description: 'Dropdown icon',
|
||||
},
|
||||
titleClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: 'Title css classes',
|
||||
},
|
||||
menuClasses: {
|
||||
type: [String, Object],
|
||||
description: 'Menu css classes',
|
||||
},
|
||||
menuOnRight: {
|
||||
type: Boolean,
|
||||
description: 'Whether menu should appear on the right',
|
||||
},
|
||||
hasToggle: {
|
||||
type: Boolean,
|
||||
description: 'Whether dropdown has arrow icon shown',
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleDropDown() {
|
||||
this.isOpen = !this.isOpen
|
||||
this.$emit('change', this.isOpen)
|
||||
},
|
||||
closeDropDown() {
|
||||
this.isOpen = false
|
||||
this.$emit('change', false)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dropdown {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<div class="header" :class="{ [`bg-${type}`]: type }">
|
||||
<b-container fluid>
|
||||
<div class="header-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-header',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'success',
|
||||
description: 'Header background type',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-pagination
|
||||
first-number
|
||||
last-number
|
||||
:per-page="perPage"
|
||||
:size="size"
|
||||
:value="value"
|
||||
@change="(val) => $emit('change', val)"
|
||||
:align="align"
|
||||
:total-rows="total"
|
||||
>
|
||||
<template v-slot:prev-text>
|
||||
<a class="page-link" aria-label="Previous">
|
||||
<span aria-hidden="true">
|
||||
<i class="fa fa-angle-left" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
<template v-slot:next-text>
|
||||
<a class="page-link" aria-label="Next">
|
||||
<span aria-hidden="true">
|
||||
<i class="fa fa-angle-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
</b-pagination>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-pagination',
|
||||
props: {
|
||||
pageCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
description: 'Pagination page count. This should be specified in combination with perPage',
|
||||
},
|
||||
perPage: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
description: 'Pagination per page. Should be specified with total or pageCount',
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
description:
|
||||
'Can be specified instead of pageCount. The page count in this case will be total/perPage',
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
description: 'Pagination value',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Pagination size',
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Pagination alignment (e.g center|start|end)',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,79 +0,0 @@
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div :class="`progress-${type}`" v-if="showLabel">
|
||||
<div class="progress-label">
|
||||
<slot name="label">
|
||||
<span>{{ label }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="progress-percentage">
|
||||
<slot>
|
||||
<span>{{ value }}%</span>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<b-progress :size="size" :class="[progressClasses]" :style="`height: ${height}px`">
|
||||
<b-progress-bar :class="computedClasses" :value="value"></b-progress-bar>
|
||||
</b-progress>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-progress',
|
||||
props: {
|
||||
striped: {
|
||||
type: Boolean,
|
||||
description: 'Whether progress is striped',
|
||||
},
|
||||
animated: {
|
||||
type: Boolean,
|
||||
description: 'Whether progress is animated (works only with `striped` prop together)',
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
description: 'Progress label (shown on the left above progress)',
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
description: 'Progress line height',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
description: 'Progress type (e.g danger, primary etc)',
|
||||
},
|
||||
showLabel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
progressClasses: {
|
||||
type: [Array, String],
|
||||
default: '',
|
||||
description: 'Progress css classes',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator: (value) => {
|
||||
return value >= 0 && value <= 100
|
||||
},
|
||||
description: 'Progress value',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
computedClasses() {
|
||||
return [
|
||||
{ 'progress-bar-striped': this.striped },
|
||||
{ 'progress-bar-animated': this.animated },
|
||||
{ [`bg-${this.type}`]: this.type },
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,92 +0,0 @@
|
||||
<template>
|
||||
<div class="slider" :disabled="disabled"></div>
|
||||
</template>
|
||||
<script>
|
||||
import noUiSlider from 'nouislider'
|
||||
|
||||
export default {
|
||||
name: 'base-slider',
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Array, Number],
|
||||
description: 'slider value',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'whether the slider is disabled',
|
||||
},
|
||||
start: {
|
||||
type: [Number, Array],
|
||||
default: 0,
|
||||
description:
|
||||
'[noUi Slider start](https://refreshless.com/nouislider/slider-options/#section-start)',
|
||||
},
|
||||
connect: {
|
||||
type: [Boolean, Array],
|
||||
default: () => [true, false],
|
||||
description:
|
||||
'[noUi Slider connect](https://refreshless.com/nouislider/slider-options/#section-connect)',
|
||||
},
|
||||
range: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
min: 0,
|
||||
max: 100,
|
||||
}
|
||||
},
|
||||
description:
|
||||
'[noUi Slider range](https://refreshless.com/nouislider/slider-values/#section-range)',
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
},
|
||||
description: '[noUi Slider options](https://refreshless.com/nouislider/slider-options/)',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
slider: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createSlider() {
|
||||
noUiSlider.create(this.$el, {
|
||||
start: this.value || this.start,
|
||||
connect: Array.isArray(this.value) ? true : this.connect,
|
||||
range: this.range,
|
||||
...this.options,
|
||||
})
|
||||
const slider = this.$el.noUiSlider
|
||||
slider.on('slide', () => {
|
||||
const value = slider.get()
|
||||
if (value !== this.value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.createSlider()
|
||||
},
|
||||
watch: {
|
||||
value(newValue, oldValue) {
|
||||
const slider = this.$el.noUiSlider
|
||||
const sliderValue = slider.get()
|
||||
if (newValue !== oldValue && sliderValue !== newValue) {
|
||||
if (Array.isArray(sliderValue) && Array.isArray(newValue)) {
|
||||
if (oldValue.length === newValue.length && oldValue.every((v, i) => v === newValue[i])) {
|
||||
slider.set(newValue)
|
||||
}
|
||||
} else {
|
||||
slider.set(newValue)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<table class="table tablesorter" :class="tableClass">
|
||||
<thead :class="theadClasses">
|
||||
<tr>
|
||||
<slot name="columns" :columns="columns">
|
||||
<th v-for="column in columns" :key="column">{{ column }}</th>
|
||||
</slot>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody :class="tbodyClasses">
|
||||
<tr v-for="(item, index) in data" :key="index">
|
||||
<slot :row="item" :index="index">
|
||||
<td v-for="(column, index) in columns" :key="index">
|
||||
{{ itemValue(item, column) }}
|
||||
</td>
|
||||
</slot>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-table',
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'Table columns',
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'Table data',
|
||||
},
|
||||
type: {
|
||||
type: String, // striped | hover
|
||||
default: '',
|
||||
description: 'Whether table is striped or hover type',
|
||||
},
|
||||
theadClasses: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: '<thead> css classes',
|
||||
},
|
||||
tbodyClasses: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: '<tbody> css classes',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
tableClass() {
|
||||
return this.type && `table-${this.type}`
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hasValue(item, column) {
|
||||
return item[column.toLowerCase()] !== 'undefined'
|
||||
},
|
||||
itemValue(item, column) {
|
||||
return item[column.toLowerCase()]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<nav aria-label="breadcrumb">
|
||||
<b-breadcrumb :class="[{ [`bg-${type}`]: type }, listClasses]">
|
||||
<slot></slot>
|
||||
</b-breadcrumb>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'breadcrumb',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Breadcrumb background type',
|
||||
},
|
||||
listClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'Breadcrumb list classes',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<b-breadcrumb-item :active="active">
|
||||
<slot></slot>
|
||||
</b-breadcrumb-item>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'breadcrumb-item',
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether breadcrumb item is active',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<bread-crumb list-classes="breadcrumb-links breadcrumb-dark">
|
||||
<bread-crumb-item>
|
||||
<router-link to="/overview">
|
||||
<i class="fas fa-home"></i>
|
||||
</router-link>
|
||||
</bread-crumb-item>
|
||||
<bread-crumb-item
|
||||
v-for="(route, index) in $route.matched.slice()"
|
||||
:key="route.name"
|
||||
:active="index === $route.matched.length - 1"
|
||||
style="display: inline-block"
|
||||
>
|
||||
<router-link :to="{ name: route.name }" v-if="index < $route.matched.length - 1">
|
||||
{{ route.name }}
|
||||
</router-link>
|
||||
<span v-else>{{ route.name }}</span>
|
||||
</bread-crumb-item>
|
||||
</bread-crumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BreadCrumb from './Breadcrumb'
|
||||
import BreadCrumbItem from './BreadcrumbItem'
|
||||
|
||||
export default {
|
||||
name: 'route-breadcrumb',
|
||||
components: {
|
||||
BreadCrumb,
|
||||
BreadCrumbItem,
|
||||
},
|
||||
methods: {
|
||||
getBreadName(route) {
|
||||
return route.name
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -1,38 +0,0 @@
|
||||
<template>
|
||||
<div class="btn-group-toggle" data-toggle="buttons">
|
||||
<label class="btn" :class="[{ active: value }, buttonClasses]">
|
||||
<input v-model="model" type="checkbox" checked="" autocomplete="off" />
|
||||
<slot></slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'button-checkbox',
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
description: 'Checked value',
|
||||
},
|
||||
buttonClasses: {
|
||||
type: [String, Object],
|
||||
description: 'Inner button css classes',
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('change', val)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,55 +0,0 @@
|
||||
<template>
|
||||
<div class="btn-group-toggle" data-toggle="buttons">
|
||||
<label
|
||||
v-for="(option, index) in options"
|
||||
:key="index"
|
||||
class="btn"
|
||||
:class="[{ active: value === option.value }, buttonClasses]"
|
||||
>
|
||||
<input
|
||||
:value="option.value"
|
||||
v-model="model"
|
||||
type="radio"
|
||||
id="option1"
|
||||
autocomplete="off"
|
||||
checked=""
|
||||
/>
|
||||
{{ option.label }}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'button-radio-group',
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
description: 'Radio options. Should be an array of objects {value: "", label: ""}',
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
description: 'Radio value',
|
||||
},
|
||||
buttonClasses: {
|
||||
type: [String, Object],
|
||||
description: 'Inner button css classes',
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('change', val)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<b-card
|
||||
no-body
|
||||
:class="[
|
||||
{ 'card-lift--hover': hover },
|
||||
{ shadow: shadow },
|
||||
{ [`shadow-${shadowSize}`]: shadowSize },
|
||||
{ [`bg-gradient-${gradient}`]: gradient },
|
||||
{ [`bg-${type}`]: type },
|
||||
]"
|
||||
>
|
||||
<slot name="image"></slot>
|
||||
<b-card-header :class="headerClasses" v-if="$slots.header">
|
||||
<slot name="header"></slot>
|
||||
</b-card-header>
|
||||
<b-card-body :class="bodyClasses" v-if="!noBody">
|
||||
<slot></slot>
|
||||
</b-card-body>
|
||||
|
||||
<slot v-if="noBody"></slot>
|
||||
|
||||
<b-card-footer :class="footerClasses" v-if="$slots.footer">
|
||||
<slot name="footer"></slot>
|
||||
</b-card-footer>
|
||||
</b-card>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'card',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
description: 'Card type',
|
||||
},
|
||||
gradient: {
|
||||
type: String,
|
||||
description: 'Card background gradient type (warning,danger etc)',
|
||||
},
|
||||
hover: {
|
||||
type: Boolean,
|
||||
description: 'Whether card should move on hover',
|
||||
},
|
||||
shadow: {
|
||||
type: Boolean,
|
||||
description: 'Whether card has shadow',
|
||||
},
|
||||
shadowSize: {
|
||||
type: String,
|
||||
description: 'Card shadow size',
|
||||
},
|
||||
noBody: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether card should have wrapper body class',
|
||||
},
|
||||
bodyClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: 'Card body css classes',
|
||||
},
|
||||
headerClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: 'Card header css classes',
|
||||
},
|
||||
footerClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: 'Card footer css classes',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<card class="card-stats" :show-footer-line="true">
|
||||
<b-row>
|
||||
<b-col>
|
||||
<slot>
|
||||
<h5 class="card-title text-uppercase text-muted mb-0" v-if="title">
|
||||
{{ title }}
|
||||
</h5>
|
||||
<span class="h2 font-weight-bold mb-0" v-if="subTitle">
|
||||
{{ subTitle }}
|
||||
</span>
|
||||
</slot>
|
||||
</b-col>
|
||||
|
||||
<b-col cols="auto" v-if="$slots.icon || icon">
|
||||
<slot name="icon">
|
||||
<div
|
||||
class="icon icon-shape text-white rounded-circle shadow"
|
||||
:class="[`bg-${type}`, iconClasses]"
|
||||
>
|
||||
<i :class="icon"></i>
|
||||
</div>
|
||||
</slot>
|
||||
</b-col>
|
||||
<b-col cols="auto" v-if="$slots.img || img">
|
||||
<slot name="img">
|
||||
<img :src="img" width="80" />
|
||||
</slot>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<p class="mt-3 mb-0 text-sm">
|
||||
<slot name="footer"></slot>
|
||||
</p>
|
||||
</card>
|
||||
</template>
|
||||
<script>
|
||||
import Card from './Card.vue'
|
||||
|
||||
export default {
|
||||
name: 'stats-card',
|
||||
components: {
|
||||
Card,
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
},
|
||||
icon: String,
|
||||
img: String,
|
||||
title: String,
|
||||
subTitle: String,
|
||||
iconClasses: [String, Array],
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,30 +0,0 @@
|
||||
import { Bar, mixins } from 'vue-chartjs'
|
||||
import globalOptionsMixin from '@/components/Charts/globalOptionsMixin'
|
||||
|
||||
export default {
|
||||
name: 'bar-chart',
|
||||
extends: Bar,
|
||||
mixins: [mixins.reactiveProp, globalOptionsMixin],
|
||||
props: {
|
||||
extraOptions: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ctx: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
'chartData',
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) {
|
||||
this.renderChart(this.chartData, this.extraOptions)
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
},
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
import { Line, mixins } from 'vue-chartjs'
|
||||
import globalOptionsMixin from '@/components/Charts/globalOptionsMixin'
|
||||
export default {
|
||||
name: 'line-chart',
|
||||
extends: Line,
|
||||
mixins: [mixins.reactiveProp, globalOptionsMixin],
|
||||
props: {
|
||||
extraOptions: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ctx: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
'chartData',
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) {
|
||||
this.renderChart(this.chartData, this.extraOptions)
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
},
|
||||
}
|
||||
@ -1,234 +0,0 @@
|
||||
import { parseOptions } from '@/components/Charts/optionHelpers'
|
||||
import Chart from 'chart.js'
|
||||
|
||||
export const Charts = {
|
||||
mode: 'light', // (themeMode) ? themeMode : 'light';
|
||||
fonts: {
|
||||
base: 'Open Sans',
|
||||
},
|
||||
colors: {
|
||||
gray: {
|
||||
100: '#f6f9fc',
|
||||
200: '#e9ecef',
|
||||
300: '#dee2e6',
|
||||
400: '#ced4da',
|
||||
500: '#adb5bd',
|
||||
600: '#8898aa',
|
||||
700: '#525f7f',
|
||||
800: '#32325d',
|
||||
900: '#212529',
|
||||
},
|
||||
theme: {
|
||||
default: '#172b4d',
|
||||
primary: '#5e72e4',
|
||||
secondary: '#f4f5f7',
|
||||
info: '#11cdef',
|
||||
success: '#2dce89',
|
||||
danger: '#f5365c',
|
||||
warning: '#fb6340',
|
||||
},
|
||||
black: '#12263F',
|
||||
white: '#FFFFFF',
|
||||
transparent: 'transparent',
|
||||
},
|
||||
}
|
||||
|
||||
function chartOptions() {
|
||||
const { colors, mode, fonts } = Charts
|
||||
// Options
|
||||
const options = {
|
||||
defaults: {
|
||||
global: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
defaultColor: mode === 'dark' ? colors.gray[700] : colors.gray[600],
|
||||
defaultFontColor: mode === 'dark' ? colors.gray[700] : colors.gray[600],
|
||||
defaultFontFamily: fonts.base,
|
||||
defaultFontSize: 13,
|
||||
layout: {
|
||||
padding: 0,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
padding: 16,
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
radius: 0,
|
||||
backgroundColor: colors.theme.primary,
|
||||
},
|
||||
line: {
|
||||
tension: 0.4,
|
||||
borderWidth: 4,
|
||||
borderColor: colors.theme.primary,
|
||||
backgroundColor: colors.transparent,
|
||||
borderCapStyle: 'rounded',
|
||||
},
|
||||
rectangle: {
|
||||
backgroundColor: colors.theme.warning,
|
||||
},
|
||||
arc: {
|
||||
backgroundColor: colors.theme.primary,
|
||||
borderColor: mode === 'dark' ? colors.gray[800] : colors.white,
|
||||
borderWidth: 4,
|
||||
},
|
||||
},
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
},
|
||||
pie: {
|
||||
tooltips: {
|
||||
mode: 'point',
|
||||
},
|
||||
},
|
||||
doughnut: {
|
||||
tooltips: {
|
||||
mode: 'point',
|
||||
},
|
||||
cutoutPercentage: 83,
|
||||
legendCallback: function (chart) {
|
||||
const data = chart.data
|
||||
let content = ''
|
||||
|
||||
data.labels.forEach(function (label, index) {
|
||||
const bgColor = data.datasets[0].backgroundColor[index]
|
||||
|
||||
content += '<span class="chart-legend-item">'
|
||||
content +=
|
||||
'<i class="chart-legend-indicator" style="background-color: ' + bgColor + '"></i>'
|
||||
content += label
|
||||
content += '</span>'
|
||||
})
|
||||
|
||||
return content
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// yAxes
|
||||
Chart.scaleService.updateScaleDefaults('linear', {
|
||||
gridLines: {
|
||||
borderDash: [2],
|
||||
borderDashOffset: [2],
|
||||
color: mode === 'dark' ? colors.gray[900] : colors.gray[200],
|
||||
drawBorder: false,
|
||||
drawTicks: true,
|
||||
zeroLineWidth: 1,
|
||||
zeroLineColor: mode === 'dark' ? colors.gray[900] : colors.gray[200],
|
||||
zeroLineBorderDash: [2],
|
||||
zeroLineBorderDashOffset: [2],
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
padding: 10,
|
||||
callback: function (value) {
|
||||
if (!(value % 10)) {
|
||||
return value
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// xAxes
|
||||
Chart.scaleService.updateScaleDefaults('category', {
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
drawOnChartArea: false,
|
||||
drawTicks: false,
|
||||
lineWidth: 1,
|
||||
zeroLineWidth: 1,
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
},
|
||||
maxBarThickness: 10,
|
||||
})
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
let initialized = false
|
||||
|
||||
export function initGlobalOptions() {
|
||||
if (initialized) {
|
||||
return
|
||||
}
|
||||
parseOptions(Chart, chartOptions())
|
||||
initialized = true
|
||||
}
|
||||
|
||||
export const basicOptions = {
|
||||
maintainAspectRatio: false,
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
responsive: true,
|
||||
}
|
||||
export const blueChartOptions = {
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
color: Charts.colors.gray[700],
|
||||
zeroLineColor: Charts.colors.gray[700],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export const lineChartOptionsBlue = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest',
|
||||
},
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.0)',
|
||||
zeroLineColor: 'transparent',
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 60,
|
||||
suggestedMax: 125,
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.1)',
|
||||
zeroLineColor: 'transparent',
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
import { initGlobalOptions } from '@/components/Charts/config'
|
||||
import './roundedCornersExtension'
|
||||
export default {
|
||||
mounted() {
|
||||
initGlobalOptions()
|
||||
},
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
// Parse global options
|
||||
export function parseOptions(parent, options) {
|
||||
for (const item in options) {
|
||||
if (typeof options[item] !== 'object') {
|
||||
parent[item] = options[item]
|
||||
} else {
|
||||
parseOptions(parent[item], options[item])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,126 +0,0 @@
|
||||
//
|
||||
// Chart extension for making the bars rounded
|
||||
// Code from: https://codepen.io/jedtrow/full/ygRYgo
|
||||
//
|
||||
import Chart from 'chart.js'
|
||||
Chart.elements.Rectangle.prototype.draw = function () {
|
||||
const ctx = this._chart.ctx
|
||||
const vm = this._view
|
||||
let left, right, top, bottom, signX, signY, borderSkipped
|
||||
let borderWidth = vm.borderWidth
|
||||
// Set Radius Here
|
||||
// If radius is large enough to cause drawing errors a max radius is imposed
|
||||
const cornerRadius = 6
|
||||
|
||||
if (!vm.horizontal) {
|
||||
// bar
|
||||
left = vm.x - vm.width / 2
|
||||
right = vm.x + vm.width / 2
|
||||
top = vm.y
|
||||
bottom = vm.base
|
||||
signX = 1
|
||||
signY = bottom > top ? 1 : -1
|
||||
borderSkipped = vm.borderSkipped || 'bottom'
|
||||
} else {
|
||||
// horizontal bar
|
||||
left = vm.base
|
||||
right = vm.x
|
||||
top = vm.y - vm.height / 2
|
||||
bottom = vm.y + vm.height / 2
|
||||
signX = right > left ? 1 : -1
|
||||
signY = 1
|
||||
borderSkipped = vm.borderSkipped || 'left'
|
||||
}
|
||||
|
||||
// Canvas doesn't allow us to stroke inside the width so we can
|
||||
// adjust the sizes to fit if we're setting a stroke on the line
|
||||
if (borderWidth) {
|
||||
// borderWidth shold be less than bar width and bar height.
|
||||
const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom))
|
||||
borderWidth = borderWidth > barSize ? barSize : borderWidth
|
||||
const halfStroke = borderWidth / 2
|
||||
// Adjust borderWidth when bar top position is near vm.base(zero).
|
||||
const borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0)
|
||||
const borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0)
|
||||
const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0)
|
||||
const borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0)
|
||||
// not become a vertical line?
|
||||
if (borderLeft !== borderRight) {
|
||||
top = borderTop
|
||||
bottom = borderBottom
|
||||
}
|
||||
// not become a horizontal line?
|
||||
if (borderTop !== borderBottom) {
|
||||
left = borderLeft
|
||||
right = borderRight
|
||||
}
|
||||
}
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = vm.backgroundColor
|
||||
ctx.strokeStyle = vm.borderColor
|
||||
ctx.lineWidth = borderWidth
|
||||
|
||||
// Corner points, from bottom-left to bottom-right clockwise
|
||||
// | 1 2 |
|
||||
// | 0 3 |
|
||||
const corners = [
|
||||
[left, bottom],
|
||||
[left, top],
|
||||
[right, top],
|
||||
[right, bottom],
|
||||
]
|
||||
|
||||
// Find first (starting) corner with fallback to 'bottom'
|
||||
const borders = ['bottom', 'left', 'top', 'right']
|
||||
let startCorner = borders.indexOf(borderSkipped, 0)
|
||||
if (startCorner === -1) {
|
||||
startCorner = 0
|
||||
}
|
||||
|
||||
function cornerAt(index) {
|
||||
return corners[(startCorner + index) % 4]
|
||||
}
|
||||
|
||||
// Draw rectangle from 'startCorner'
|
||||
let corner = cornerAt(0)
|
||||
ctx.moveTo(corner[0], corner[1])
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
corner = cornerAt(i)
|
||||
let nextCornerId = i + 1
|
||||
if (nextCornerId === 4) {
|
||||
nextCornerId = 0
|
||||
}
|
||||
|
||||
const width = corners[2][0] - corners[1][0]
|
||||
const height = corners[0][1] - corners[1][1]
|
||||
const x = corners[1][0]
|
||||
const y = corners[1][1]
|
||||
|
||||
let radius = cornerRadius
|
||||
|
||||
// Fix radius being too large
|
||||
if (radius > height / 2) {
|
||||
radius = height / 2
|
||||
}
|
||||
if (radius > width / 2) {
|
||||
radius = width / 2
|
||||
}
|
||||
|
||||
ctx.moveTo(x + radius, y)
|
||||
ctx.lineTo(x + width - radius, y)
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
|
||||
ctx.lineTo(x + width, y + height - radius)
|
||||
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height)
|
||||
ctx.lineTo(x + radius, y + height)
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
|
||||
ctx.lineTo(x, y + radius)
|
||||
ctx.quadraticCurveTo(x, y, x + radius, y)
|
||||
}
|
||||
|
||||
ctx.fill()
|
||||
if (borderWidth) {
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
|
||||
import CloseButton from './CloseButton'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
describe('CloseButton', () => {
|
||||
let wrapper
|
||||
const propsData = {
|
||||
target: 'Target',
|
||||
expanded: false,
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(CloseButton, { localVue, propsData })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('emmits click event', () => {
|
||||
wrapper.find('.navbar-toggler').trigger('click')
|
||||
expect(wrapper.emitted('click')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="navbar-toggler"
|
||||
data-toggle="collapse"
|
||||
@click="handleClick"
|
||||
:data-target="`#${target}`"
|
||||
:aria-controls="target"
|
||||
:aria-expanded="expanded"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'close-button',
|
||||
props: {
|
||||
target: {
|
||||
type: [String, Number],
|
||||
description: 'Close button target element',
|
||||
},
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
description: 'Whether button is expanded (aria-expanded attribute)',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick(evt) {
|
||||
this.$emit('click', evt)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,78 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="custom-control custom-checkbox"
|
||||
:class="[{ disabled: disabled }, { [`custom-checkbox-${type}`]: type }, inlineClass]"
|
||||
>
|
||||
<input
|
||||
:id="cbId"
|
||||
class="custom-control-input"
|
||||
:class="inputClasses"
|
||||
type="checkbox"
|
||||
:disabled="disabled"
|
||||
v-model="model"
|
||||
/>
|
||||
<label :for="cbId" class="custom-control-label">
|
||||
<slot>
|
||||
<span v-if="inline"> </span>
|
||||
</slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-checkbox',
|
||||
model: {
|
||||
prop: 'checked',
|
||||
},
|
||||
props: {
|
||||
checked: {
|
||||
type: [Array, Boolean],
|
||||
description: 'Whether checkbox is checked',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
description: 'Whether checkbox is disabled',
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
description: 'Whether checkbox is inline',
|
||||
},
|
||||
inputClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: 'Checkbox input classes',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
description: 'Checkbox type (e.g info, danger etc)',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cbId: '',
|
||||
touched: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.checked
|
||||
},
|
||||
set(check) {
|
||||
if (!this.touched) {
|
||||
this.touched = true
|
||||
}
|
||||
this.$emit('input', check)
|
||||
},
|
||||
},
|
||||
inlineClass() {
|
||||
if (this.inline) {
|
||||
return `form-check-inline`
|
||||
}
|
||||
return ''
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.cbId = Math.random().toString(16).slice(2)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,187 +0,0 @@
|
||||
<template>
|
||||
<validation-provider
|
||||
:rules="rules"
|
||||
:name="name"
|
||||
v-bind="$attrs"
|
||||
v-slot="{ errors, valid, invalid, validated }"
|
||||
>
|
||||
<b-form-group>
|
||||
<slot name="label">
|
||||
<label v-if="label" :class="labelClasses">
|
||||
{{ label }}
|
||||
</label>
|
||||
</slot>
|
||||
<div
|
||||
:class="[
|
||||
{ 'input-group': hasIcon },
|
||||
{ focused: focused },
|
||||
{ 'input-group-alternative': alternative },
|
||||
{ 'has-label': label || $slots.label },
|
||||
inputGroupClasses,
|
||||
]"
|
||||
>
|
||||
<div v-if="prependIcon || $slots.prepend" class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<slot name="prepend">
|
||||
<i :class="prependIcon"></i>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<slot v-bind="slotData">
|
||||
<input
|
||||
:value="value"
|
||||
:type="type"
|
||||
v-on="listeners"
|
||||
v-bind="$attrs"
|
||||
:valid="valid"
|
||||
:required="required"
|
||||
class="form-control"
|
||||
:class="[
|
||||
{ 'is-valid': valid && validated && successMessage },
|
||||
{ 'is-invalid': invalid && validated },
|
||||
inputClasses,
|
||||
]"
|
||||
/>
|
||||
</slot>
|
||||
<div v-if="appendIcon || $slots.append" class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<slot name="append">
|
||||
<i :class="appendIcon"></i>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<slot name="infoBlock"></slot>
|
||||
</div>
|
||||
<slot name="success">
|
||||
<div class="valid-feedback" v-if="valid && validated && successMessage">
|
||||
{{ successMessage }}
|
||||
</div>
|
||||
</slot>
|
||||
<slot name="error">
|
||||
<div v-if="errors[0]" class="invalid-feedback" style="display: block">
|
||||
{{ errors[0] }}
|
||||
</div>
|
||||
</slot>
|
||||
</b-form-group>
|
||||
</validation-provider>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
name: 'base-input',
|
||||
props: {
|
||||
required: {
|
||||
type: Boolean,
|
||||
description: 'Whether input is required (adds an asterix *)',
|
||||
},
|
||||
group: {
|
||||
type: Boolean,
|
||||
description: 'Whether input is an input group (manual override in special cases)',
|
||||
},
|
||||
alternative: {
|
||||
type: Boolean,
|
||||
description: 'Whether input is of alternative layout',
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
description: 'Input label (text before input)',
|
||||
},
|
||||
error: {
|
||||
type: String,
|
||||
description: 'Input error (below input)',
|
||||
},
|
||||
successMessage: {
|
||||
type: String,
|
||||
description: 'Input success message',
|
||||
default: '',
|
||||
},
|
||||
labelClasses: {
|
||||
type: String,
|
||||
description: 'Input label css classes',
|
||||
default: 'form-control-label',
|
||||
},
|
||||
inputClasses: {
|
||||
type: String,
|
||||
description: 'Input css classes',
|
||||
},
|
||||
inputGroupClasses: {
|
||||
type: String,
|
||||
description: 'Input group css classes',
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
description: 'Input value',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
description: 'Input type',
|
||||
default: 'text',
|
||||
},
|
||||
appendIcon: {
|
||||
type: String,
|
||||
description: 'Append icon (right)',
|
||||
},
|
||||
prependIcon: {
|
||||
type: String,
|
||||
description: 'Prepend icon (left)',
|
||||
},
|
||||
rules: {
|
||||
type: [String, Array, Object],
|
||||
description: 'Vee validate validation rules',
|
||||
default: '',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
description: 'Input name (used for validation)',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
focused: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
listeners() {
|
||||
return {
|
||||
...this.$listeners,
|
||||
input: this.updateValue,
|
||||
focus: this.onFocus,
|
||||
blur: this.onBlur,
|
||||
}
|
||||
},
|
||||
slotData() {
|
||||
return {
|
||||
focused: this.focused,
|
||||
error: this.error,
|
||||
...this.listeners,
|
||||
}
|
||||
},
|
||||
hasIcon() {
|
||||
const { append, prepend } = this.$slots
|
||||
return (
|
||||
append !== undefined ||
|
||||
prepend !== undefined ||
|
||||
this.appendIcon !== undefined ||
|
||||
this.prependIcon !== undefined ||
|
||||
this.group
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateValue(evt) {
|
||||
const value = evt.target.value
|
||||
this.$emit('input', value)
|
||||
},
|
||||
onFocus(evt) {
|
||||
this.focused = true
|
||||
this.$emit('focus', evt)
|
||||
},
|
||||
onBlur(evt) {
|
||||
this.focused = false
|
||||
this.$emit('blur', evt)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,64 +0,0 @@
|
||||
<template>
|
||||
<div class="custom-control custom-radio" :class="[inlineClass, { disabled: disabled }]">
|
||||
<input
|
||||
:id="cbId"
|
||||
class="custom-control-input"
|
||||
type="radio"
|
||||
:disabled="disabled"
|
||||
:value="name"
|
||||
v-model="model"
|
||||
/>
|
||||
<label :for="cbId" class="custom-control-label">
|
||||
<slot>
|
||||
<span v-if="inline"> </span>
|
||||
</slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-radio',
|
||||
props: {
|
||||
name: {
|
||||
type: [String, Number],
|
||||
description: 'Radio label',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
description: 'Whether radio is disabled',
|
||||
},
|
||||
value: {
|
||||
type: [String, Boolean],
|
||||
description: 'Radio value',
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
description: 'Whether radio is inline',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cbId: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
},
|
||||
},
|
||||
inlineClass() {
|
||||
if (this.inline) {
|
||||
return `form-check-inline`
|
||||
}
|
||||
return ''
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.cbId = Math.random().toString(16).slice(2)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,127 +0,0 @@
|
||||
<template>
|
||||
<slide-y-up-transition :duration="animationDuration">
|
||||
<b-modal
|
||||
class="modal fade"
|
||||
ref="app-modal"
|
||||
:size="size"
|
||||
:hide-header="!$slots.header"
|
||||
:modal-class="[{ 'modal-mini': type === 'mini' }, ...modalClasses]"
|
||||
@mousedown.self="closeModal"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
centered
|
||||
@close="closeModal"
|
||||
@hide="closeModal"
|
||||
:header-class="headerClasses"
|
||||
:footer-class="footerClasses"
|
||||
:content-class="[gradient ? `bg-gradient-${gradient}` : '', ...modalContentClasses]"
|
||||
:body-class="bodyClasses"
|
||||
:aria-hidden="!show"
|
||||
>
|
||||
<template v-slot:modal-header>
|
||||
<slot name="header"></slot>
|
||||
<slot name="close-button">
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
v-if="showClose"
|
||||
@click="closeModal"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
>
|
||||
<span :aria-hidden="!show">×</span>
|
||||
</button>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<slot />
|
||||
|
||||
<template v-slot:modal-footer>
|
||||
<slot name="footer"></slot>
|
||||
</template>
|
||||
</b-modal>
|
||||
</slide-y-up-transition>
|
||||
</template>
|
||||
<script>
|
||||
import { SlideYUpTransition } from 'vue2-transitions'
|
||||
|
||||
export default {
|
||||
name: 'modal',
|
||||
components: {
|
||||
SlideYUpTransition,
|
||||
},
|
||||
props: {
|
||||
show: Boolean,
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
validator(value) {
|
||||
const acceptedValues = ['', 'notice', 'mini']
|
||||
return acceptedValues.indexOf(value) !== -1
|
||||
},
|
||||
description: 'Modal type (notice|mini|"") ',
|
||||
},
|
||||
modalClasses: {
|
||||
type: [Object, String],
|
||||
description: 'Modal dialog css classes',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
description: 'Modal size',
|
||||
validator(value) {
|
||||
const acceptedValues = ['', 'sm', 'lg']
|
||||
return acceptedValues.indexOf(value) !== -1
|
||||
},
|
||||
},
|
||||
modalContentClasses: {
|
||||
type: [Object, String],
|
||||
description: 'Modal dialog content css classes',
|
||||
},
|
||||
gradient: {
|
||||
type: String,
|
||||
description: 'Modal gradient type (danger, primary etc)',
|
||||
},
|
||||
headerClasses: {
|
||||
type: [Object, String],
|
||||
description: 'Modal Header css classes',
|
||||
},
|
||||
bodyClasses: {
|
||||
type: [Object, String],
|
||||
description: 'Modal Body css classes',
|
||||
},
|
||||
footerClasses: {
|
||||
type: [Object, String],
|
||||
description: 'Modal Footer css classes',
|
||||
},
|
||||
animationDuration: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
description: 'Modal transition duration',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
closeModal() {
|
||||
this.$emit('update:show', false)
|
||||
this.$emit('close')
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
show(val) {
|
||||
if (val) {
|
||||
this.$refs['app-modal'].show()
|
||||
} else {
|
||||
this.$refs['app-modal'].hide()
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.modal-backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.6) !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,80 +0,0 @@
|
||||
<template>
|
||||
<!--Notice modal-->
|
||||
<modal
|
||||
:show.sync="$store.state.modals"
|
||||
modal-classes="modal-danger"
|
||||
modal-content-classes="bg-gradient-danger"
|
||||
>
|
||||
<h6 slot="header" class="modal-title">Your attention is required</h6>
|
||||
|
||||
<div class="py-3 text-center">
|
||||
<form ref="form" @submit.stop.prevent="handleSubmit">
|
||||
<b-form-group
|
||||
label="Name"
|
||||
label-for="name-input"
|
||||
invalid-feedback="Name is required"
|
||||
:state="nameState"
|
||||
>
|
||||
<b-form-input id="name-input" v-model="name" :state="nameState" required></b-form-input>
|
||||
</b-form-group>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<template slot="footer">
|
||||
<base-button type="white">Ok</base-button>
|
||||
<base-button type="link" class="ml-auto" @click="$store.state.modals = false">
|
||||
abbrechen
|
||||
</base-button>
|
||||
</template>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'modal',
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
nameState: null,
|
||||
submittedNames: [],
|
||||
}
|
||||
},
|
||||
/* Modal */
|
||||
checkFormValidity() {
|
||||
const valid = this.$refs.form.checkValidity()
|
||||
this.nameState = valid
|
||||
return valid
|
||||
},
|
||||
resetModal() {
|
||||
this.name = ''
|
||||
this.nameState = null
|
||||
},
|
||||
handleOk(bvModalEvt) {
|
||||
// Prevent modal from closing
|
||||
bvModalEvt.preventDefault()
|
||||
// Trigger submit handler
|
||||
this.handleSubmit()
|
||||
},
|
||||
handleSubmit() {
|
||||
// Exit when the form isn't valid
|
||||
if (!this.checkFormValidity()) {
|
||||
return
|
||||
}
|
||||
// Push the name to submitted names
|
||||
this.submittedNames.push(this.name)
|
||||
this.$store.state.modals = false
|
||||
this.$store.commit('loginAsAdmin')
|
||||
this.$router.push('/AdminOverview')
|
||||
|
||||
// Hide the modal manually
|
||||
this.$nextTick(() => {
|
||||
this.$bvModal.hide('modal-prevent-closing')
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.modal-backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.6) !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,120 +0,0 @@
|
||||
<template>
|
||||
<b-navbar toggleable :class="classes">
|
||||
<div :class="containerClasses">
|
||||
<slot name="brand"></slot>
|
||||
|
||||
<slot name="toggle-button">
|
||||
<button
|
||||
class="navbar-toggler collapsed"
|
||||
v-if="hasMenu"
|
||||
type="button"
|
||||
@click="toggleMenu"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-bar navbar-kebab"></span>
|
||||
<span class="navbar-toggler-bar navbar-kebab"></span>
|
||||
<span class="navbar-toggler-bar navbar-kebab"></span>
|
||||
</button>
|
||||
</slot>
|
||||
|
||||
<b-navbar-toggle target="nav-text-collapse" @click.stop="toggleMenu"></b-navbar-toggle>
|
||||
|
||||
<b-collapse
|
||||
is-nav
|
||||
id="nav-text-collapse"
|
||||
class="navbar-custom-collapse collapse"
|
||||
:class="menuClasses"
|
||||
:visible="show"
|
||||
v-click-outside="closeMenu"
|
||||
>
|
||||
<slot :close-menu="closeMenu"></slot>
|
||||
</b-collapse>
|
||||
</div>
|
||||
</b-navbar>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-nav',
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description:
|
||||
'Whether navbar menu is shown (valid for viewports < specified by `expand` prop)',
|
||||
},
|
||||
transparent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether navbar is transparent',
|
||||
},
|
||||
expand: {
|
||||
type: String,
|
||||
default: 'lg',
|
||||
description: 'Breakpoint where nav should expand',
|
||||
},
|
||||
menuClasses: {
|
||||
type: [String, Object, Array],
|
||||
default: '',
|
||||
description: 'Navbar menu (items) classes. Can be used to align menu items to the right/left',
|
||||
},
|
||||
containerClasses: {
|
||||
type: [String, Object, Array],
|
||||
default: 'container',
|
||||
description:
|
||||
'Container classes. Can be used to control container classes (contains both navbar brand and menu items)',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
validator(value) {
|
||||
return [
|
||||
'',
|
||||
'dark',
|
||||
'success',
|
||||
'danger',
|
||||
'warning',
|
||||
'white',
|
||||
'primary',
|
||||
'light',
|
||||
'info',
|
||||
'vue',
|
||||
].includes(value)
|
||||
},
|
||||
description: 'Navbar color type',
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: 'show',
|
||||
event: 'change',
|
||||
},
|
||||
computed: {
|
||||
classes() {
|
||||
const color = `bg-${this.type}`
|
||||
const classes = [
|
||||
{ 'navbar-transparent': this.transparent },
|
||||
{ [`navbar-expand-${this.expand}`]: this.expand },
|
||||
]
|
||||
if (this.position) {
|
||||
classes.push(`navbar-${this.position}`)
|
||||
}
|
||||
if (!this.transparent) {
|
||||
classes.push(color)
|
||||
}
|
||||
return classes
|
||||
},
|
||||
hasMenu() {
|
||||
return this.$slots.default
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleMenu() {
|
||||
this.$emit('change', !this.show)
|
||||
},
|
||||
closeMenu() {
|
||||
this.$emit('change', false)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,194 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
@click="tryClose"
|
||||
data-notify="container"
|
||||
class="alert alert-notify alert-dismissible"
|
||||
:class="[{ 'alert-with-icon': icon }, verticalAlign, horizontalAlign, alertType]"
|
||||
role="alert"
|
||||
:style="customPosition"
|
||||
data-notify-position="top-center"
|
||||
>
|
||||
<template v-if="icon || $slots.icon">
|
||||
<slot name="icon">
|
||||
<span class="alert-icon" data-notify="icon">
|
||||
<i :class="icon"></i>
|
||||
</span>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<span class="alert-text">
|
||||
<span v-if="title" class="title">
|
||||
<b>
|
||||
{{ title }}
|
||||
<br />
|
||||
</b>
|
||||
</span>
|
||||
<span v-if="message" v-html="message"></span>
|
||||
<content-render v-if="!message && component" :component="component"></content-render>
|
||||
</span>
|
||||
|
||||
<slot name="dismiss-icon">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close" @click="close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'notification',
|
||||
components: {
|
||||
contentRender: {
|
||||
props: ['component'],
|
||||
render: function (createElement) {
|
||||
return createElement(this.component)
|
||||
},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
message: String,
|
||||
title: {
|
||||
type: String,
|
||||
description: 'Notification title',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
description: 'Notification icon',
|
||||
},
|
||||
verticalAlign: {
|
||||
type: String,
|
||||
default: 'top',
|
||||
validator: (value) => {
|
||||
const acceptedValues = ['top', 'bottom']
|
||||
return acceptedValues.indexOf(value) !== -1
|
||||
},
|
||||
description: 'Vertical alignment of notification (top|bottom)',
|
||||
},
|
||||
horizontalAlign: {
|
||||
type: String,
|
||||
default: 'right',
|
||||
validator: (value) => {
|
||||
const acceptedValues = ['left', 'center', 'right']
|
||||
return acceptedValues.indexOf(value) !== -1
|
||||
},
|
||||
description: 'Horizontal alignment of notification (left|center|right)',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'info',
|
||||
validator: (value) => {
|
||||
const acceptedValues = ['default', 'info', 'primary', 'danger', 'warning', 'success']
|
||||
return acceptedValues.indexOf(value) !== -1
|
||||
},
|
||||
description:
|
||||
'Notification type of notification (default|info|primary|danger|warning|success)',
|
||||
},
|
||||
timeout: {
|
||||
type: Number,
|
||||
default: 5000,
|
||||
validator: (value) => {
|
||||
return value >= 0
|
||||
},
|
||||
description: 'Notification timeout (closes after X milliseconds). Default is 5000 (5s)',
|
||||
},
|
||||
timestamp: {
|
||||
type: Date,
|
||||
default: () => new Date(),
|
||||
description:
|
||||
'Notification timestamp (used internally to handle notification removal correctly)',
|
||||
},
|
||||
component: {
|
||||
type: [Object, Function],
|
||||
description: 'Custom content component. Cane be a `.vue` component or render function',
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
description: 'Whether to show close button',
|
||||
},
|
||||
closeOnClick: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
description: "Whether to close notification when clicking it' body",
|
||||
},
|
||||
clickHandler: {
|
||||
type: Function,
|
||||
description: 'Custom notification click handler',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
elmHeight: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasIcon() {
|
||||
return this.icon && this.icon.length > 0
|
||||
},
|
||||
alertType() {
|
||||
return `alert-${this.type}`
|
||||
},
|
||||
customPosition() {
|
||||
const initialMargin = 20
|
||||
const alertHeight = this.elmHeight + 10
|
||||
let sameAlertsCount = this.$notifications.state.filter((alert) => {
|
||||
return (
|
||||
alert.horizontalAlign === this.horizontalAlign &&
|
||||
alert.verticalAlign === this.verticalAlign &&
|
||||
alert.timestamp <= this.timestamp
|
||||
)
|
||||
}).length
|
||||
if (this.$notifications.settings.overlap) {
|
||||
sameAlertsCount = 1
|
||||
}
|
||||
const pixels = (sameAlertsCount - 1) * alertHeight + initialMargin
|
||||
const styles = {}
|
||||
if (this.verticalAlign === 'top') {
|
||||
styles.top = `${pixels}px`
|
||||
} else {
|
||||
styles.bottom = `${pixels}px`
|
||||
}
|
||||
return styles
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit('close', this.timestamp)
|
||||
},
|
||||
tryClose(evt) {
|
||||
if (this.clickHandler) {
|
||||
this.clickHandler(evt, this)
|
||||
}
|
||||
if (this.closeOnClick) {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.elmHeight = this.$el.clientHeight
|
||||
if (this.timeout) {
|
||||
setTimeout(this.close, this.timeout)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.notifications .alert {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
|
||||
&[data-notify='container'] {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
&.center {
|
||||
margin: 0 auto;
|
||||
}
|
||||
&.left {
|
||||
left: 20px;
|
||||
}
|
||||
&.right {
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<div class="notifications">
|
||||
<slide-y-up-transition :duration="transitionDuration" group mode="out-in">
|
||||
<notification
|
||||
v-for="notification in notifications"
|
||||
v-bind="notification"
|
||||
:clickHandler="notification.onClick"
|
||||
:key="notification.timestamp.getTime()"
|
||||
@close="removeNotification"
|
||||
></notification>
|
||||
</slide-y-up-transition>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Notification from './Notification.vue'
|
||||
import { SlideYUpTransition } from 'vue2-transitions'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SlideYUpTransition,
|
||||
Notification,
|
||||
},
|
||||
props: {
|
||||
transitionDuration: {
|
||||
type: Number,
|
||||
default: 200,
|
||||
},
|
||||
overlap: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
notifications: this.$notifications.state,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
removeNotification(timestamp) {
|
||||
this.$notifications.removeNotification(timestamp)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$notifications.settings.overlap = this.overlap
|
||||
},
|
||||
watch: {
|
||||
overlap: function (newVal) {
|
||||
this.$notifications.settings.overlap = newVal
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,66 +0,0 @@
|
||||
import Notifications from './Notifications.vue'
|
||||
|
||||
const NotificationStore = {
|
||||
state: [], // here the notifications will be added
|
||||
settings: {
|
||||
overlap: false,
|
||||
verticalAlign: 'top',
|
||||
horizontalAlign: 'right',
|
||||
type: 'info',
|
||||
timeout: 5000,
|
||||
closeOnClick: true,
|
||||
showClose: true,
|
||||
},
|
||||
setOptions(options) {
|
||||
this.settings = Object.assign(this.settings, options)
|
||||
},
|
||||
removeNotification(timestamp) {
|
||||
const indexToDelete = this.state.findIndex((n) => n.timestamp === timestamp)
|
||||
if (indexToDelete !== -1) {
|
||||
this.state.splice(indexToDelete, 1)
|
||||
}
|
||||
},
|
||||
addNotification(notification) {
|
||||
if (typeof notification === 'string' || notification instanceof String) {
|
||||
notification = { message: notification }
|
||||
}
|
||||
notification.timestamp = new Date()
|
||||
notification.timestamp.setMilliseconds(
|
||||
notification.timestamp.getMilliseconds() + this.state.length,
|
||||
)
|
||||
notification = Object.assign({}, this.settings, notification)
|
||||
this.state.push(notification)
|
||||
},
|
||||
notify(notification) {
|
||||
if (Array.isArray(notification)) {
|
||||
notification.forEach((notificationInstance) => {
|
||||
this.addNotification(notificationInstance)
|
||||
})
|
||||
} else {
|
||||
this.addNotification(notification)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const NotificationsPlugin = {
|
||||
install(Vue, options) {
|
||||
const app = new Vue({
|
||||
data: {
|
||||
notificationStore: NotificationStore,
|
||||
},
|
||||
methods: {
|
||||
notify(notification) {
|
||||
this.notificationStore.notify(notification)
|
||||
},
|
||||
},
|
||||
})
|
||||
Vue.prototype.$notify = app.notify
|
||||
Vue.prototype.$notifications = app.notificationStore
|
||||
Vue.component('Notifications', Notifications)
|
||||
if (options) {
|
||||
NotificationStore.setOptions(options)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default NotificationsPlugin
|
||||
53
frontend/src/components/PaginationButtons.spec.js
Normal file
53
frontend/src/components/PaginationButtons.spec.js
Normal file
@ -0,0 +1,53 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PaginationButtons from './PaginationButtons'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
describe('PaginationButtons', () => {
|
||||
let wrapper
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(PaginationButtons, { localVue })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div.pagination-buttons').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has previous page button disabled by default', () => {
|
||||
expect(wrapper.find('button.previous-page').attributes('disabled')).toBe('disabled')
|
||||
})
|
||||
|
||||
it('has bext page button disabled by default', () => {
|
||||
expect(wrapper.find('button.next-page').attributes('disabled')).toBe('disabled')
|
||||
})
|
||||
|
||||
it('shows the text "1 / 1" by default"', () => {
|
||||
expect(wrapper.find('p.text-center').text()).toBe('1 / 1')
|
||||
})
|
||||
|
||||
describe('with active buttons', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({
|
||||
hasNext: true,
|
||||
hasPrevious: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('emits show-previous when previous page button is clicked', () => {
|
||||
wrapper.find('button.previous-page').trigger('click')
|
||||
expect(wrapper.emitted('show-previous')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('emits show-next when next page button is clicked', () => {
|
||||
wrapper.find('button.next-page').trigger('click')
|
||||
expect(wrapper.emitted('show-next')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
30
frontend/src/components/PaginationButtons.vue
Normal file
30
frontend/src/components/PaginationButtons.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="pagination-buttons">
|
||||
<b-row class="m-4">
|
||||
<b-col class="text-right">
|
||||
<b-button class="previous-page" :disabled="!hasPrevious" @click="$emit('show-previous')">
|
||||
<b-icon icon="chevron-left" variant="primary"></b-icon>
|
||||
</b-button>
|
||||
</b-col>
|
||||
<b-col cols="2">
|
||||
<p class="text-center pt-2">{{ currentPage }} / {{ totalPages }}</p>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-button class="next-page" :disabled="!hasNext" @click="$emit('show-next')">
|
||||
<b-icon icon="chevron-right" variant="primary"></b-icon>
|
||||
</b-button>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'PaginationButtons',
|
||||
props: {
|
||||
hasNext: { type: Boolean, default: false },
|
||||
hasPrevious: { type: Boolean, default: false },
|
||||
totalPages: { type: Number, default: 1 },
|
||||
currentPage: { type: Number, default: 1 },
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<vue-bootstrap-typeahead v-model="query" :data="users" @change="getUser" />
|
||||
</template>
|
||||
<script>
|
||||
import VueBootstrapTypeahead from 'vue-bootstrap-typeahead'
|
||||
|
||||
// Global registration
|
||||
// Vue.component('vue-bootstrap-typeahead', VueBootstrapTypeahead)
|
||||
|
||||
// OR
|
||||
|
||||
// Local registration
|
||||
export default {
|
||||
name: 'SearchUser',
|
||||
components: {
|
||||
VueBootstrapTypeahead,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
user: '',
|
||||
users: [
|
||||
'Bob',
|
||||
'Alice',
|
||||
'Bernd',
|
||||
'Dario',
|
||||
'Alex',
|
||||
'Pauls',
|
||||
'Ulf',
|
||||
'Delaware',
|
||||
'Florida',
|
||||
'Georgia',
|
||||
'Hawaii',
|
||||
'Idaho',
|
||||
'Illnois',
|
||||
'Indiana',
|
||||
'Iowa',
|
||||
'Kansas',
|
||||
'Kentucky',
|
||||
'Louisiana',
|
||||
'Maine',
|
||||
'Maryland',
|
||||
'Massachusetts',
|
||||
'Michigan',
|
||||
'Minnesota',
|
||||
'Mississippi',
|
||||
'Missouri',
|
||||
'Montana',
|
||||
'Nebraska',
|
||||
'Nevada',
|
||||
'New Hampshire',
|
||||
'New Jersey',
|
||||
'New Mexico',
|
||||
'New York',
|
||||
'North Carolina',
|
||||
'North Dakota',
|
||||
'Ohio',
|
||||
'Oklahoma',
|
||||
'Oregon',
|
||||
'Pennsylvania',
|
||||
'Rhode Island',
|
||||
'South Carolina',
|
||||
'South Dakota',
|
||||
'Tennessee',
|
||||
'Texas',
|
||||
'Utah',
|
||||
'Vermont',
|
||||
'Virginia',
|
||||
'Washington',
|
||||
'West Virginia',
|
||||
'Wisconsin',
|
||||
'Wyoming',
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getUser() {
|
||||
alert(this.data.user)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -41,6 +41,19 @@ describe('SideBar', () => {
|
||||
expect(wrapper.find('#sidenav-main').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
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('balance', () => {
|
||||
it('shows em-dash as balance while loading', () => {
|
||||
expect(wrapper.find('div.row.text-center').text()).toBe('— GDD')
|
||||
@ -55,19 +68,6 @@ describe('SideBar', () => {
|
||||
})
|
||||
})
|
||||
|
||||
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')
|
||||
|
||||
@ -14,13 +14,11 @@
|
||||
</b-row>
|
||||
<slot name="mobile-right">
|
||||
<ul class="nav align-items-center d-md-none">
|
||||
<a slot="title-container" class="nav-link" role="button">
|
||||
<div class="media align-items-center">
|
||||
<span class="avatar avatar-sm">
|
||||
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="media align-items-center">
|
||||
<span class="avatar avatar-sm">
|
||||
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
|
||||
</span>
|
||||
</div>
|
||||
</ul>
|
||||
</slot>
|
||||
<slot></slot>
|
||||
@ -71,15 +69,15 @@
|
||||
</template>
|
||||
<script>
|
||||
import NavbarToggleButton from '@/components/NavbarToggleButton'
|
||||
import VueQrcode from 'vue-qrcode'
|
||||
import LanguageSwitch from '@/components/LanguageSwitch.vue'
|
||||
import VueQrcode from 'vue-qrcode'
|
||||
|
||||
export default {
|
||||
name: 'sidebar',
|
||||
components: {
|
||||
NavbarToggleButton,
|
||||
VueQrcode,
|
||||
LanguageSwitch,
|
||||
VueQrcode,
|
||||
},
|
||||
props: {
|
||||
logo: {
|
||||
|
||||
@ -10,12 +10,10 @@ const SidebarStore = {
|
||||
},
|
||||
toggleMinimize() {
|
||||
document.body.classList.toggle('sidebar-mini')
|
||||
// we simulate the window Resize so the charts will get updated in realtime.
|
||||
const simulateWindowResize = setInterval(() => {
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
}, 180)
|
||||
|
||||
// we stop the simulation of Window Resize after the animations are completed
|
||||
setTimeout(() => {
|
||||
clearInterval(simulateWindowResize)
|
||||
}, 1000)
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="tab-pane"
|
||||
v-show="active"
|
||||
:id="id || title"
|
||||
:class="{ active: active }"
|
||||
:aria-expanded="active"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'tab-pane',
|
||||
props: ['title', 'id'],
|
||||
inject: ['addTab', 'removeTab'],
|
||||
data() {
|
||||
return {
|
||||
active: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.addTab(this)
|
||||
},
|
||||
destroyed() {
|
||||
if (this.$el && this.$el.parentNode) {
|
||||
this.$el.parentNode.removeChild(this.$el)
|
||||
}
|
||||
this.removeTab(this)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -1,155 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
{ 'col-md-4': vertical && !tabNavWrapperClasses },
|
||||
{ 'col-12': centered && !tabNavWrapperClasses },
|
||||
tabNavWrapperClasses,
|
||||
]"
|
||||
>
|
||||
<b-nav
|
||||
class="nav-pills"
|
||||
role="tablist"
|
||||
:class="[
|
||||
`nav-pills-${type}`,
|
||||
{ 'flex-column': vertical },
|
||||
{ 'justify-content-center': centered },
|
||||
tabNavClasses,
|
||||
]"
|
||||
>
|
||||
<b-nav-item
|
||||
v-for="tab in tabs"
|
||||
class="active"
|
||||
data-toggle="tab"
|
||||
role="tablist"
|
||||
:active="tab.active"
|
||||
:key="tab.id"
|
||||
:href="`#${tab.id}`"
|
||||
@click.prevent="activateTab(tab)"
|
||||
:aria-expanded="tab.active"
|
||||
>
|
||||
<tab-item-content :tab="tab"></tab-item-content>
|
||||
</b-nav-item>
|
||||
</b-nav>
|
||||
</div>
|
||||
<div
|
||||
class="tab-content"
|
||||
:class="[
|
||||
{ 'tab-space': !vertical },
|
||||
{ 'col-md-8': vertical && !tabContentClasses },
|
||||
tabContentClasses,
|
||||
]"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'tabs',
|
||||
components: {
|
||||
TabItemContent: {
|
||||
props: ['tab'],
|
||||
render(h) {
|
||||
return h('div', [this.tab.$slots.title || this.tab.title])
|
||||
},
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
addTab: this.addTab,
|
||||
removeTab: this.removeTab,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
validator: (value) => {
|
||||
const acceptedValues = ['primary', 'info', 'success', 'warning', 'danger']
|
||||
return acceptedValues.indexOf(value) !== -1
|
||||
},
|
||||
},
|
||||
activeTab: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Active tab name',
|
||||
},
|
||||
tabNavWrapperClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'ul wrapper css classes',
|
||||
},
|
||||
tabNavClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'ul css classes',
|
||||
},
|
||||
tabContentClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'tab content css classes',
|
||||
},
|
||||
vertical: Boolean,
|
||||
centered: Boolean,
|
||||
value: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabs: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
findAndActivateTab(title) {
|
||||
const tabToActivate = this.tabs.find((t) => t.title === title)
|
||||
if (tabToActivate) {
|
||||
this.activateTab(tabToActivate)
|
||||
}
|
||||
},
|
||||
activateTab(tab) {
|
||||
if (this.handleClick) {
|
||||
this.handleClick(tab)
|
||||
}
|
||||
this.deactivateTabs()
|
||||
tab.active = true
|
||||
},
|
||||
deactivateTabs() {
|
||||
this.tabs.forEach((tab) => {
|
||||
tab.active = false
|
||||
})
|
||||
},
|
||||
addTab(tab) {
|
||||
const index = this.$slots.default.indexOf(tab.$vnode)
|
||||
if (!this.activeTab && index === 0) {
|
||||
tab.active = true
|
||||
}
|
||||
if (this.activeTab === tab.name) {
|
||||
tab.active = true
|
||||
}
|
||||
this.tabs.splice(index, 0, tab)
|
||||
},
|
||||
removeTab(tab) {
|
||||
const tabs = this.tabs
|
||||
const index = tabs.indexOf(tab)
|
||||
if (index > -1) {
|
||||
tabs.splice(index, 1)
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (this.value) {
|
||||
this.findAndActivateTab(this.value)
|
||||
}
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
value(newVal) {
|
||||
this.findAndActivateTab(newVal)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -1,50 +1,8 @@
|
||||
import BaseCheckbox from './Inputs/BaseCheckbox.vue'
|
||||
import BaseAlert from './BaseAlert.vue'
|
||||
import BaseRadio from './Inputs/BaseRadio.vue'
|
||||
import BaseInput from './Inputs/BaseInput.vue'
|
||||
import Badge from './Badge'
|
||||
import BaseProgress from './BaseProgress.vue'
|
||||
import BaseButton from './BaseButton.vue'
|
||||
|
||||
import BaseDropdown from './BaseDropdown.vue'
|
||||
import BaseTable from './BaseTable.vue'
|
||||
|
||||
import Card from './Cards/Card.vue'
|
||||
import StatsCard from './Cards/StatsCard.vue'
|
||||
import BaseNav from './Navbar/BaseNav'
|
||||
import NavbarToggleButton from './Navbar/NavbarToggleButton'
|
||||
|
||||
import TabPane from './Tabs/Tab.vue'
|
||||
import Tabs from './Tabs/Tabs.vue'
|
||||
import Collapse from './Collapse/Collapse.vue'
|
||||
import CollapseItem from './Collapse/CollapseItem.vue'
|
||||
import Modal from './Modal.vue'
|
||||
import BaseSlider from './BaseSlider.vue'
|
||||
|
||||
import BasePagination from './BasePagination.vue'
|
||||
|
||||
import SidebarPlugin from './SidebarPlugin'
|
||||
|
||||
export {
|
||||
BaseCheckbox,
|
||||
Badge,
|
||||
BaseAlert,
|
||||
BaseProgress,
|
||||
BasePagination,
|
||||
BaseRadio,
|
||||
BaseInput,
|
||||
Card,
|
||||
StatsCard,
|
||||
BaseTable,
|
||||
BaseDropdown,
|
||||
SidebarPlugin,
|
||||
BaseNav,
|
||||
NavbarToggleButton,
|
||||
TabPane,
|
||||
Tabs,
|
||||
Modal,
|
||||
BaseSlider,
|
||||
BaseButton,
|
||||
Collapse,
|
||||
CollapseItem,
|
||||
}
|
||||
export { SidebarPlugin, NavbarToggleButton, Collapse, CollapseItem }
|
||||
|
||||
@ -20,17 +20,25 @@
|
||||
},
|
||||
"decay": "Vergänglichkeit",
|
||||
"form": {
|
||||
"cancel":"Abbrechen",
|
||||
"cancel": "Abbrechen",
|
||||
"reset": "Zurücksetzen",
|
||||
"close":"schließen",
|
||||
"close": "schließen",
|
||||
"edit": "bearbeiten",
|
||||
"save": "speichern",
|
||||
"receiver":"Empfänger",
|
||||
"sender":"Absender",
|
||||
"username":"Username",
|
||||
"firstname":"Vorname",
|
||||
"lastname":"Nachname",
|
||||
"description": "Beschreibung",
|
||||
"email":"E-Mail",
|
||||
"email_repeat":"eMail wiederholen",
|
||||
"password":"Passwort",
|
||||
"password_repeat":"Passwort wiederholen",
|
||||
"passwordRepeat":"Passwort wiederholen",
|
||||
"password_old":"altes Passwort",
|
||||
"password_new":"neues Passwort",
|
||||
"password_new_repeat":"neues Passwort wiederholen",
|
||||
"change": "ändern",
|
||||
"amount":"Betrag",
|
||||
"memo":"Nachricht für den Empfänger",
|
||||
"message":"Nachricht",
|
||||
@ -48,9 +56,10 @@
|
||||
"send_transaction_success":"Deine Transaktion wurde erfolgreich ausgeführt",
|
||||
"send_transaction_error":"Leider konnte die Transaktion nicht ausgeführt werden!",
|
||||
"validation": {
|
||||
"double": "Das Feld {field} muss eine Dezimalzahl mit zwei Nachkommastellen sein",
|
||||
"gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein",
|
||||
"is-not": "Du kannst dir selbst keine Gradidos überweisen"
|
||||
}
|
||||
},
|
||||
"change_username_info": "Das ändern des Usernamens bedarf mehrerer Schritte."
|
||||
},
|
||||
"error": {
|
||||
"error":"Fehler"
|
||||
@ -96,12 +105,13 @@
|
||||
"add_work":"neuer Gemeinschaftsbeitrag"
|
||||
},
|
||||
"profil": {
|
||||
"transactions":"transactions",
|
||||
"activity": {
|
||||
"chart":"Gemeinschaftsstunden Chart",
|
||||
"new":"Neue Gemeinschaftsstunden eintragen",
|
||||
"list":"Meine Gemeinschaftsstunden Liste"
|
||||
}
|
||||
},
|
||||
"user-data": {
|
||||
"change-success": "Deine Daten wurden gespeichert."
|
||||
}
|
||||
},
|
||||
"navbar" : {
|
||||
"my-profil":"Mein Profil",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"message": "hello gradido !!",
|
||||
"welcome":"Welcome!",
|
||||
"community": "Gemeinschaft",
|
||||
"community": "Community",
|
||||
"logout":"Logout",
|
||||
"login":"Login",
|
||||
"signup": "Sign up",
|
||||
@ -23,14 +23,22 @@
|
||||
"cancel":"Cancel",
|
||||
"reset": "Reset",
|
||||
"close":"Close",
|
||||
"edit": "Edit",
|
||||
"save": "save",
|
||||
"receiver":"Receiver",
|
||||
"sender":"Sender",
|
||||
"username":"Username",
|
||||
"firstname":"Firstname",
|
||||
"lastname":"Lastname",
|
||||
"description": "Description",
|
||||
"email":"Email",
|
||||
"email_repeat":"Repeat Email",
|
||||
"password":"Password",
|
||||
"password_repeat":"Repeat password",
|
||||
"passwordRepeat":"Repeat password",
|
||||
"password_old":"Old password",
|
||||
"password_new":"New password",
|
||||
"password_new_repeat":"Repeat new password",
|
||||
"change": "change",
|
||||
"amount":"Amount",
|
||||
"memo":"Message for the recipient",
|
||||
"message":"Message",
|
||||
@ -48,9 +56,10 @@
|
||||
"send_transaction_success":"Your transaction was successfully completed",
|
||||
"send_transaction_error":"Unfortunately, the transaction could not be executed!",
|
||||
"validation": {
|
||||
"double": "The {field} field must be a decimal with two digits",
|
||||
"gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits",
|
||||
"is-not": "You cannot send Gradidos to yourself"
|
||||
}
|
||||
},
|
||||
"change_username_info": "Changing the username requires several steps."
|
||||
},
|
||||
"error": {
|
||||
"error":"Error"
|
||||
@ -98,10 +107,12 @@
|
||||
"profil": {
|
||||
"transactions":"transactions",
|
||||
"activity": {
|
||||
"chart":"Community Hours Chart",
|
||||
"new":"Register new community hours",
|
||||
"list":"My Community Hours List"
|
||||
}
|
||||
},
|
||||
"user-data": {
|
||||
"change-success": "Your data has been saved."
|
||||
}
|
||||
},
|
||||
"navbar" : {
|
||||
"my-profil":"My profile",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user