mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into community_ipv6_localhost
This commit is contained in:
commit
ada873f80e
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -50,7 +50,7 @@ jobs:
|
|||||||
##########################################################################
|
##########################################################################
|
||||||
- name: login server | Build `test` image
|
- name: login server | Build `test` image
|
||||||
run: |
|
run: |
|
||||||
docker build --target login_server_debug -t "gradido/login_server:test" -f ./login_server/Dockerfile.debug login_server/
|
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
|
docker save "gradido/login_server:test" > /tmp/login_server.tar
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
@ -212,7 +212,7 @@ jobs:
|
|||||||
report_name: Coverage Frontend
|
report_name: Coverage Frontend
|
||||||
type: lcov
|
type: lcov
|
||||||
result_path: ./coverage/lcov.info
|
result_path: ./coverage/lcov.info
|
||||||
min_coverage: 15
|
min_coverage: 19
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
|
|
||||||
#test:
|
#test:
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
|||||||
*.log
|
*.log
|
||||||
/node_modules/*
|
/node_modules/*
|
||||||
.vscode
|
.vscode
|
||||||
|
messages.pot
|
||||||
|
.skeema
|
||||||
|
nbproject
|
||||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -27,5 +27,10 @@
|
|||||||
|
|
||||||
[submodule "community_server/src/protobuf"]
|
[submodule "community_server/src/protobuf"]
|
||||||
path = community_server/src/protobuf
|
path = community_server/src/protobuf
|
||||||
url = git@github.com:gradido/gradido_protocol.git
|
url = https://github.com/gradido/gradido_protocol.git
|
||||||
|
[submodule "login_server/dependencies/libsodium"]
|
||||||
|
path = login_server/dependencies/libsodium
|
||||||
|
url = https://github.com/jedisct1/libsodium.git
|
||||||
|
[submodule "login_server/src/proto"]
|
||||||
|
path = login_server/src/proto
|
||||||
|
url = https://github.com/gradido/gradido_protocol.git
|
||||||
|
|||||||
130
CHANGELOG.md
130
CHANGELOG.md
@ -4,8 +4,138 @@ All notable changes to this project will be documented in this file. Dates are d
|
|||||||
|
|
||||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||||
|
|
||||||
|
#### [1.0.1](https://github.com/gradido/gradido/compare/1.0.0...1.0.1)
|
||||||
|
|
||||||
|
- add try catch blocks to prevent login-server from crashing [`22ff220`](https://github.com/gradido/gradido/commit/22ff22072956f8b843037c75c5b16b7ff5d6a2a3)
|
||||||
|
- fix [`14a4243`](https://github.com/gradido/gradido/commit/14a424347817b1fe6912a113bffd70e55d688112)
|
||||||
|
|
||||||
|
### [1.0.0](https://github.com/gradido/gradido/compare/0.9.4...1.0.0)
|
||||||
|
|
||||||
|
> 14 May 2021
|
||||||
|
|
||||||
|
- Login build alpine [`#423`](https://github.com/gradido/gradido/pull/423)
|
||||||
|
- Release fix [`#428`](https://github.com/gradido/gradido/pull/428)
|
||||||
|
- Send button only click [`#427`](https://github.com/gradido/gradido/pull/427)
|
||||||
|
- use new function for balance overview in old frontend, update balance… [`#422`](https://github.com/gradido/gradido/pull/422)
|
||||||
|
- thx.vue coloured background removed. design adapted to app [`#426`](https://github.com/gradido/gradido/pull/426)
|
||||||
|
- translation password rules in Register.vue and ResetPasswort.vue fixed [`#424`](https://github.com/gradido/gradido/pull/424)
|
||||||
|
- 06x style [`#419`](https://github.com/gradido/gradido/pull/419)
|
||||||
|
- feat: Dash is Shown When Balance is Loading [`#396`](https://github.com/gradido/gradido/pull/396)
|
||||||
|
- refactor: Split GddSend into Components [`#415`](https://github.com/gradido/gradido/pull/415)
|
||||||
|
- fix: Set Maximum Transactions Loaded to 1000 [`#395`](https://github.com/gradido/gradido/pull/395)
|
||||||
|
- BUG : preRELEASE : thx transaction false [`#394`](https://github.com/gradido/gradido/pull/394)
|
||||||
|
- feat: Validation of Input Fields of GddSend [`#386`](https://github.com/gradido/gradido/pull/386)
|
||||||
|
- add validation, check if user has tried to send themself gradidos [`#277`](https://github.com/gradido/gradido/pull/277)
|
||||||
|
- fix link generation [`#347`](https://github.com/gradido/gradido/pull/347)
|
||||||
|
- Community start decay [`#387`](https://github.com/gradido/gradido/pull/387)
|
||||||
|
- transaction error message, translations [`#388`](https://github.com/gradido/gradido/pull/388)
|
||||||
|
- docu: locales schöpfen-mysql befehl [`#392`](https://github.com/gradido/gradido/pull/392)
|
||||||
|
- Fix: QR Scanner Hide [`#380`](https://github.com/gradido/gradido/pull/380)
|
||||||
|
- change design- dark-blue of text-ligth [`#381`](https://github.com/gradido/gradido/pull/381)
|
||||||
|
- spelling & translation [`#385`](https://github.com/gradido/gradido/pull/385)
|
||||||
|
- 350 6 login [`#383`](https://github.com/gradido/gradido/pull/383)
|
||||||
|
- fix: breakout error [`#375`](https://github.com/gradido/gradido/pull/375)
|
||||||
|
- 233-Support-Button fix, and col error fix [`#343`](https://github.com/gradido/gradido/pull/343)
|
||||||
|
- fix: membersarea open in a new tap [`#370`](https://github.com/gradido/gradido/pull/370)
|
||||||
|
- 00x table footer componente [`#345`](https://github.com/gradido/gradido/pull/345)
|
||||||
|
- clickevent from icon to button [`#364`](https://github.com/gradido/gradido/pull/364)
|
||||||
|
- 404 link to login page fix [`#366`](https://github.com/gradido/gradido/pull/366)
|
||||||
|
- bug: session_id vs sessionId [`#365`](https://github.com/gradido/gradido/pull/365)
|
||||||
|
- eslint rule standard [`#344`](https://github.com/gradido/gradido/pull/344)
|
||||||
|
- don't show decays smaller than 0,01 GDD [`#329`](https://github.com/gradido/gradido/pull/329)
|
||||||
|
- 338 - mt-5 margin top 5 eingebunden [`#341`](https://github.com/gradido/gradido/pull/341)
|
||||||
|
- feat: Update Transactions When GddTable Is Rendered [`#339`](https://github.com/gradido/gradido/pull/339)
|
||||||
|
- my profile auskommentiert [`#337`](https://github.com/gradido/gradido/pull/337)
|
||||||
|
- give balance as float value in GDD (not longer GDD cent) [`#273`](https://github.com/gradido/gradido/pull/273)
|
||||||
|
- fix error with password reset email [`#276`](https://github.com/gradido/gradido/pull/276)
|
||||||
|
- transaction.show_all in en.json hinzugefügt [`#335`](https://github.com/gradido/gradido/pull/335)
|
||||||
|
- refactor: Add Paramerts to ListTransactions API Call [`#332`](https://github.com/gradido/gradido/pull/332)
|
||||||
|
- css abstände vom rand in mobilen style [`#272`](https://github.com/gradido/gradido/pull/272)
|
||||||
|
- error messages are displayed [`#304`](https://github.com/gradido/gradido/pull/304)
|
||||||
|
- cancel to reset, form rest event added [`#334`](https://github.com/gradido/gradido/pull/334)
|
||||||
|
- remove from error messages because its no longer exist [`#330`](https://github.com/gradido/gradido/pull/330)
|
||||||
|
- xx deleted [`#333`](https://github.com/gradido/gradido/pull/333)
|
||||||
|
- fix bug on Login group add host [`#274`](https://github.com/gradido/gradido/pull/274)
|
||||||
|
- transactionslist load and icon [`#324`](https://github.com/gradido/gradido/pull/324)
|
||||||
|
- THX changed to Thank you [`#305`](https://github.com/gradido/gradido/pull/305)
|
||||||
|
- fix_bug_template [`#284`](https://github.com/gradido/gradido/pull/284)
|
||||||
|
- feat: Restructure Overview [`#271`](https://github.com/gradido/gradido/pull/271)
|
||||||
|
- fix: Dynamic Balance in User Profile [`#278`](https://github.com/gradido/gradido/pull/278)
|
||||||
|
- refactor: Test and Clean Up Store [`#270`](https://github.com/gradido/gradido/pull/270)
|
||||||
|
- remove links to not work [`#267`](https://github.com/gradido/gradido/pull/267)
|
||||||
|
- change order of session_id [`#269`](https://github.com/gradido/gradido/pull/269)
|
||||||
|
- bug: Dynamic Balance [`#260`](https://github.com/gradido/gradido/pull/260)
|
||||||
|
- Fix problems with transactions in docker environment [`#261`](https://github.com/gradido/gradido/pull/261)
|
||||||
|
- update skeema call to allow also for unsafe db updates [`#250`](https://github.com/gradido/gradido/pull/250)
|
||||||
|
- turn registration on and off [`#266`](https://github.com/gradido/gradido/pull/266)
|
||||||
|
- 243 vue loader component - varante 2 [`#257`](https://github.com/gradido/gradido/pull/257)
|
||||||
|
- fix_issue_templates [`#262`](https://github.com/gradido/gradido/pull/262)
|
||||||
|
- fix_nginx_docker [`#253`](https://github.com/gradido/gradido/pull/253)
|
||||||
|
- 13_coverage [`#255`](https://github.com/gradido/gradido/pull/255)
|
||||||
|
- add language as fields which will be returned with user-object [`#244`](https://github.com/gradido/gradido/pull/244)
|
||||||
|
- add short description for target date in creation transaction [`#252`](https://github.com/gradido/gradido/pull/252)
|
||||||
|
- fix error "Integrity constraint violation: 1052 Column 'id' in where … [`#251`](https://github.com/gradido/gradido/pull/251)
|
||||||
|
- Clicks on button [`#246`](https://github.com/gradido/gradido/pull/246)
|
||||||
|
- Change css [`#231`](https://github.com/gradido/gradido/pull/231)
|
||||||
|
- feat: Reset Password [`#212`](https://github.com/gradido/gradido/pull/212)
|
||||||
|
- fix bug #221 [`#228`](https://github.com/gradido/gradido/pull/228)
|
||||||
|
- fix empty reply by empty group_id [`#227`](https://github.com/gradido/gradido/pull/227)
|
||||||
|
- Bugfix 22 04 21 [`#226`](https://github.com/gradido/gradido/pull/226)
|
||||||
|
- Rollback use prebuild dependencies [`#225`](https://github.com/gradido/gradido/pull/225)
|
||||||
|
- Docu [`#199`](https://github.com/gradido/gradido/pull/199)
|
||||||
|
- update login-server build [`#222`](https://github.com/gradido/gradido/pull/222)
|
||||||
|
- Login add language [`#220`](https://github.com/gradido/gradido/pull/220)
|
||||||
|
- User Object on Json Login [`#219`](https://github.com/gradido/gradido/pull/219)
|
||||||
|
- refactor: Remove loginAPI Call from Store [`#215`](https://github.com/gradido/gradido/pull/215)
|
||||||
|
- fix: Remove Rules for Password on Login [`#214`](https://github.com/gradido/gradido/pull/214)
|
||||||
|
- Community 15 04 2021 [`#198`](https://github.com/gradido/gradido/pull/198)
|
||||||
|
- refactor: Remove Right Menu [`#204`](https://github.com/gradido/gradido/pull/204)
|
||||||
|
- feat: Raise Frontend Test Coverage to 12% [`#206`](https://github.com/gradido/gradido/pull/206)
|
||||||
|
- refactor: Remove Cookies [`#202`](https://github.com/gradido/gradido/pull/202)
|
||||||
|
- fix_docker_compose [`#205`](https://github.com/gradido/gradido/pull/205)
|
||||||
|
- 62 pwd reset [`#203`](https://github.com/gradido/gradido/pull/203)
|
||||||
|
- workflows_refactor [`#200`](https://github.com/gradido/gradido/pull/200)
|
||||||
|
- feat: Link to Whitepaper in Content-Footer [`#196`](https://github.com/gradido/gradido/pull/196)
|
||||||
|
- update code which produce error which last fix (._.); [`#197`](https://github.com/gradido/gradido/pull/197)
|
||||||
|
- refactor: Redirects and Misuse of Children in Router [`#194`](https://github.com/gradido/gradido/pull/194)
|
||||||
|
- fix: Gradido-Akademie in Footer Links to gradido.net [`#170`](https://github.com/gradido/gradido/pull/170)
|
||||||
|
- fix register [`#160`](https://github.com/gradido/gradido/pull/160)
|
||||||
|
- Login 14.04.21 [`#175`](https://github.com/gradido/gradido/pull/175)
|
||||||
|
- coverage_no_report [`#176`](https://github.com/gradido/gradido/pull/176)
|
||||||
|
- Community 14.04.21 [`#174`](https://github.com/gradido/gradido/pull/174)
|
||||||
|
- feat: Add Coverage Check To GitHub Workflow [`#158`](https://github.com/gradido/gradido/pull/158)
|
||||||
|
- Stage2 [`#49`](https://github.com/gradido/gradido/pull/49)
|
||||||
|
- feat: Unit Test for KontoOverview [`#169`](https://github.com/gradido/gradido/pull/169)
|
||||||
|
- fix: Remove Hashtag From Route [`#167`](https://github.com/gradido/gradido/pull/167)
|
||||||
|
- documentation for reset password [`#166`](https://github.com/gradido/gradido/pull/166)
|
||||||
|
- 90 show release version in frontend [`#153`](https://github.com/gradido/gradido/pull/153)
|
||||||
|
- docu frontend menu page structur [`#159`](https://github.com/gradido/gradido/pull/159)
|
||||||
|
- userstorry_button.txt example [`#157`](https://github.com/gradido/gradido/pull/157)
|
||||||
|
- fix getBalance API call [`#147`](https://github.com/gradido/gradido/pull/147)
|
||||||
|
- Locale clear list merge master [`#119`](https://github.com/gradido/gradido/pull/119)
|
||||||
|
- fix-125-link-to-community [`#152`](https://github.com/gradido/gradido/pull/152)
|
||||||
|
- feat: Test Dashboard Layout [`#154`](https://github.com/gradido/gradido/pull/154)
|
||||||
|
- feat: Activate Coverage Report For Unit Tests In Frontend [`#156`](https://github.com/gradido/gradido/pull/156)
|
||||||
|
- Docu [`#120`](https://github.com/gradido/gradido/pull/120)
|
||||||
|
- Fix compose bug [`#138`](https://github.com/gradido/gradido/pull/138)
|
||||||
|
- feat: Test Login Form [`#113`](https://github.com/gradido/gradido/pull/113)
|
||||||
|
- at last, fix email-bug [`#134`](https://github.com/gradido/gradido/pull/134)
|
||||||
|
- Api password reset [`#82`](https://github.com/gradido/gradido/pull/82)
|
||||||
|
- Optimize login server build [`#101`](https://github.com/gradido/gradido/pull/101)
|
||||||
|
- markdown of login server api [`#111`](https://github.com/gradido/gradido/pull/111)
|
||||||
|
- Fix lineendings [`#112`](https://github.com/gradido/gradido/pull/112)
|
||||||
|
- Background color change [`#117`](https://github.com/gradido/gradido/pull/117)
|
||||||
|
- Delete unused files [`#116`](https://github.com/gradido/gradido/pull/116)
|
||||||
|
- store aufräumen teil 1 [`#115`](https://github.com/gradido/gradido/pull/115)
|
||||||
|
- add migrations table for automatic table data migration [`40a9a8c`](https://github.com/gradido/gradido/commit/40a9a8c2b587f5bef0fcc54136ed7bd13dd91b2b)
|
||||||
|
- update yarn.lock after running yarn install [`7f38c80`](https://github.com/gradido/gradido/commit/7f38c801213ad886e9d34a8d43b00ae423f5f2a0)
|
||||||
|
- use new function for balance overview in old frontend, update balance in session on every php-request [`97c570c`](https://github.com/gradido/gradido/commit/97c570c08cc51ed17a69eb8be8d987f95f3c2ce0)
|
||||||
|
|
||||||
#### [0.9.4](https://github.com/gradido/gradido/compare/0.9.3...0.9.4)
|
#### [0.9.4](https://github.com/gradido/gradido/compare/0.9.3...0.9.4)
|
||||||
|
|
||||||
|
> 30 March 2021
|
||||||
|
|
||||||
|
- Vue with nginx [`#84`](https://github.com/gradido/gradido/pull/84)
|
||||||
- Build on run [`#103`](https://github.com/gradido/gradido/pull/103)
|
- Build on run [`#103`](https://github.com/gradido/gradido/pull/103)
|
||||||
- update debug docker to use dependencies container pushed to docker hub [`1f002f4`](https://github.com/gradido/gradido/commit/1f002f4ed0b12d4b2bf63efceabe546d0c5b58ea)
|
- update debug docker to use dependencies container pushed to docker hub [`1f002f4`](https://github.com/gradido/gradido/commit/1f002f4ed0b12d4b2bf63efceabe546d0c5b58ea)
|
||||||
- removed email tasks complete [`8a143be`](https://github.com/gradido/gradido/commit/8a143be8423d7bd894d4f512848895df8b9694b0)
|
- removed email tasks complete [`8a143be`](https://github.com/gradido/gradido/commit/8a143be8423d7bd894d4f512848895df8b9694b0)
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO `migrations` (`id`, `db_version`) VALUES
|
||||||
|
(1, 2);
|
||||||
@ -6,5 +6,5 @@ INSERT INTO `transaction_types` (`id`, `name`, `text`) VALUES
|
|||||||
(5, 'group remove member', 'remove user from group, maybe he was moved elsewhere'),
|
(5, 'group remove member', 'remove user from group, maybe he was moved elsewhere'),
|
||||||
(6, 'hedera topic create', 'create new topic on hedera'),
|
(6, 'hedera topic create', 'create new topic on hedera'),
|
||||||
(7, 'hedera topic send message', 'send consensus message over hedera topic'),
|
(7, 'hedera topic send message', 'send consensus message over hedera topic'),
|
||||||
(8, 'hedera account create', 'create new account on hedera for holding some founds with unencrypted keys');
|
(8, 'hedera account create', 'create new account on hedera for holding some founds with unencrypted keys'),
|
||||||
|
(9, 'decay start', 'signalize the starting point for decay calculation, allowed only once per chain');
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE `migrations` (
|
||||||
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`db_version` int DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
CREATE TABLE `transaction_types` (
|
CREATE TABLE `transaction_types` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(90) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`text` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`text` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ use Cake\Routing\Router;
|
|||||||
use Cake\ORM\TableRegistry;
|
use Cake\ORM\TableRegistry;
|
||||||
use Cake\Core\Configure;
|
use Cake\Core\Configure;
|
||||||
use Cake\I18n\Time;
|
use Cake\I18n\Time;
|
||||||
use Cake\I18n\I18n;
|
use Cake\I18n\FrozenTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application Controller
|
* Application Controller
|
||||||
@ -156,8 +156,25 @@ class AppController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function checkForMigration($html = true)
|
||||||
|
{
|
||||||
|
$migrationsTable = TableRegistry::getTableLocator()->get('Migrations');
|
||||||
|
$last_migration = $migrationsTable->find()->last();
|
||||||
|
$current_db_version = 1;
|
||||||
|
if($last_migration) {
|
||||||
|
$current_db_version = $last_migration->db_version;
|
||||||
|
}
|
||||||
|
$php_data_version = 2;
|
||||||
|
if($current_db_version < $php_data_version) {
|
||||||
|
$this->redirect(['controller' => 'Migrations', 'action' => 'migrate', 'html' => $html, 'db_version' => $current_db_version]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function requestLogin($sessionId = 0, $redirect = true)
|
protected function requestLogin($sessionId = 0, $redirect = true)
|
||||||
{
|
{
|
||||||
|
$this->checkForMigration($redirect);
|
||||||
|
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||||
$session = $this->getRequest()->getSession();
|
$session = $this->getRequest()->getSession();
|
||||||
// check login
|
// check login
|
||||||
// disable encryption for cookies
|
// disable encryption for cookies
|
||||||
@ -191,11 +208,14 @@ class AppController extends Controller
|
|||||||
$transactionExecutings = $session->read('Transactions.executing');
|
$transactionExecutings = $session->read('Transactions.executing');
|
||||||
$transaction_can_signed = $session->read('Transactions.can_signed');
|
$transaction_can_signed = $session->read('Transactions.can_signed');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($session->read('session_id') != $session_id ||
|
if ($session->read('session_id') != $session_id ||
|
||||||
( $userStored && (!isset($userStored['id']) || !$userStored['email_checked'])) ||
|
( $userStored && (!isset($userStored['id']) || !$userStored['email_checked'])) ||
|
||||||
intval($transactionPendings) > 0 ||
|
intval($transactionPendings) > 0 ||
|
||||||
intval($transactionExecutings) > 0 ||
|
intval($transactionExecutings) > 0 ||
|
||||||
intval($transaction_can_signed > 0)) {
|
intval($transaction_can_signed > 0))
|
||||||
|
{
|
||||||
$http = new Client();
|
$http = new Client();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -227,6 +247,7 @@ class AppController extends Controller
|
|||||||
$session->write('session_id', $session_id);
|
$session->write('session_id', $session_id);
|
||||||
$stateUserTable = TableRegistry::getTableLocator()->get('StateUsers');
|
$stateUserTable = TableRegistry::getTableLocator()->get('StateUsers');
|
||||||
|
|
||||||
|
|
||||||
if (isset($json['user']['public_hex']) && $json['user']['public_hex'] != '') {
|
if (isset($json['user']['public_hex']) && $json['user']['public_hex'] != '') {
|
||||||
$public_key_bin = hex2bin($json['user']['public_hex']);
|
$public_key_bin = hex2bin($json['user']['public_hex']);
|
||||||
$stateUserQuery = $stateUserTable
|
$stateUserQuery = $stateUserTable
|
||||||
@ -254,11 +275,6 @@ class AppController extends Controller
|
|||||||
$this->Flash->error(__('error updating state user ' . json_encode($stateUser->errors())));
|
$this->Flash->error(__('error updating state user ' . json_encode($stateUser->errors())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//var_dump($stateUser);
|
|
||||||
if (count($stateUser->state_balances) > 0) {
|
|
||||||
|
|
||||||
$session->write('StateUser.balance', $stateUser->state_balances[0]->decay);
|
|
||||||
}
|
|
||||||
$session->write('StateUser.id', $stateUser->id);
|
$session->write('StateUser.id', $stateUser->id);
|
||||||
//echo $stateUser['id'];
|
//echo $stateUser['id'];
|
||||||
} else {
|
} else {
|
||||||
@ -310,6 +326,11 @@ class AppController extends Controller
|
|||||||
//continue;
|
//continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $session->read('StateUser.id')])->first();
|
||||||
|
if ($state_balance) {
|
||||||
|
$now = new FrozenTime;
|
||||||
|
$session->write('StateUser.balance', $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// no login
|
// no login
|
||||||
//die("no login");
|
//die("no login");
|
||||||
|
|||||||
@ -156,6 +156,9 @@ class AppRequestsController extends AppController
|
|||||||
if($required_fields !== true) {
|
if($required_fields !== true) {
|
||||||
return $this->returnJson($required_fields);
|
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]']);
|
||||||
|
}
|
||||||
$params['transaction_type'] = 'transfer';
|
$params['transaction_type'] = 'transfer';
|
||||||
|
|
||||||
$requestAnswear = $this->JsonRequestClient->sendRequest(json_encode($params), '/createTransaction');
|
$requestAnswear = $this->JsonRequestClient->sendRequest(json_encode($params), '/createTransaction');
|
||||||
@ -323,23 +326,33 @@ class AppRequestsController extends AppController
|
|||||||
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id'] ? $user['id'] : 0);
|
$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
|
$stateUserTransactionsQuery = $stateUserTransactionsTable
|
||||||
->find()
|
->find()
|
||||||
->where(['state_user_id' => $user['id']])
|
->where(['state_user_id' => $user['id']])
|
||||||
->order(['balance_date' => 'ASC'])
|
->order(['balance_date' => $orderDirection])
|
||||||
->contain([])
|
->contain([])
|
||||||
->limit($count)
|
->limit($count)
|
||||||
->page($page)
|
->page($page)
|
||||||
;
|
;
|
||||||
$decay = true;
|
$decay = true;
|
||||||
$transactions = [];
|
$transactions = [];
|
||||||
|
$transactions_from_db = $stateUserTransactionsQuery->toArray();
|
||||||
if($stateUserTransactionsQuery->count() > 0) {
|
if($stateUserTransactionsQuery->count() > 0) {
|
||||||
$transactions = $transactionsTable->listTransactionsHumanReadable($stateUserTransactionsQuery->toArray(), $user, $decay);
|
if($orderDirection == 'DESC') {
|
||||||
|
$transactions_from_db = array_reverse($transactions_from_db);
|
||||||
|
}
|
||||||
|
$transactions = $transactionsTable->listTransactionsHumanReadable($transactions_from_db, $user, $decay);
|
||||||
|
|
||||||
if($orderDirection == 'DESC') {
|
if($orderDirection == 'DESC') {
|
||||||
$transactions = array_reverse($transactions);
|
$transactions = array_reverse($transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $user['id']])->first();
|
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $user['id']])->first();
|
||||||
@ -348,7 +361,7 @@ class AppRequestsController extends AppController
|
|||||||
'state' => 'success',
|
'state' => 'success',
|
||||||
'transactions' => $transactions,
|
'transactions' => $transactions,
|
||||||
'transactionExecutingCount' => $session->read('Transactions.executing'),
|
'transactionExecutingCount' => $session->read('Transactions.executing'),
|
||||||
'count' => count($transactions),
|
'count' => $stateUserTransactions_total->count(),
|
||||||
'gdtSum' => $gdtSum,
|
'gdtSum' => $gdtSum,
|
||||||
'timeUsed' => microtime(true) - $startTime
|
'timeUsed' => microtime(true) - $startTime
|
||||||
];
|
];
|
||||||
@ -360,7 +373,7 @@ class AppRequestsController extends AppController
|
|||||||
$body['decay'] = 0.0;
|
$body['decay'] = 0.0;
|
||||||
} else {
|
} else {
|
||||||
$body['balance'] = $state_balance->amount;
|
$body['balance'] = $state_balance->amount;
|
||||||
$body['decay'] = $state_balance->partDecay($now);
|
$body['decay'] = $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->set('body', $body);
|
$this->set('body', $body);
|
||||||
|
|||||||
@ -4,9 +4,9 @@ namespace App\Controller;
|
|||||||
|
|
||||||
use App\Controller\AppController;
|
use App\Controller\AppController;
|
||||||
use Cake\ORM\TableRegistry;
|
use Cake\ORM\TableRegistry;
|
||||||
use Cake\Routing\Router;
|
|
||||||
use Cake\Http\Client;
|
use Cake\Http\Client;
|
||||||
use Cake\Core\Configure;
|
use Cake\Core\Configure;
|
||||||
|
use Cake\Mailer\Email;
|
||||||
|
|
||||||
use Model\Transactions\TransactionTransfer;
|
use Model\Transactions\TransactionTransfer;
|
||||||
use Model\Transactions\Transaction;
|
use Model\Transactions\Transaction;
|
||||||
@ -333,32 +333,71 @@ class JsonRequestHandlerController extends AppController {
|
|||||||
return $this->returnJson(['state' => 'success']);
|
return $this->returnJson(['state' => 'success']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function sendEMailTransactionFailed($transaction, $reason_type)
|
||||||
|
{
|
||||||
|
$disable_email = Configure::read('disableEmail', false);
|
||||||
|
if($disable_email) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
// send notification email
|
||||||
|
$noReplyEmail = Configure::read('noReplyEmail');
|
||||||
|
if($senderUser) {
|
||||||
|
try {
|
||||||
|
$email = new Email();
|
||||||
|
$emailViewBuilder = $email->viewBuilder();
|
||||||
|
$emailViewBuilder->setTemplate('notificationTransactionFailed')
|
||||||
|
->setVars(['user' => $senderUser, 'transaction' => $transaction, 'reason' => $reason_type]);
|
||||||
|
$receiverNames = $senderUser->getNames();
|
||||||
|
if($receiverNames == '' || $senderUser->email == '') {
|
||||||
|
$this->addError('TransactionCreation::sendNotificationEmail', 'to email is empty for user: ' . $senderUser->id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$email->setFrom([$noReplyEmail => 'Gradido (nicht antworten)'])
|
||||||
|
->setTo([$senderUser->email => $senderUser->getNames()])
|
||||||
|
->setSubject(__('Gradido Transaktion fehlgeschlagen!'))
|
||||||
|
->send();
|
||||||
|
} catch(Exception $e) {
|
||||||
|
$this->addAdminError('JsonRequestController', 'sendEMailTransactionFailed', [$e->getMessage(), $reason_type], $senderUser->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function putTransaction($transactionBase64) {
|
private function putTransaction($transactionBase64) {
|
||||||
$transaction = new Transaction($transactionBase64);
|
$transaction = new Transaction($transactionBase64);
|
||||||
//echo "after new transaction<br>";
|
//echo "after new transaction<br>";
|
||||||
if($transaction->hasErrors()) {
|
if($transaction->hasErrors()) {
|
||||||
|
$this->sendEMailTransactionFailed($transaction, 'parse');
|
||||||
return $this->returnJson(['state' => 'error', 'msg' => 'error parsing transaction', 'details' => $transaction->getErrors()]);
|
return $this->returnJson(['state' => 'error', 'msg' => 'error parsing transaction', 'details' => $transaction->getErrors()]);
|
||||||
}
|
}
|
||||||
//echo "after check on errors<br>";
|
//echo "after check on errors<br>";
|
||||||
if(!$transaction->validate()) {
|
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>";
|
//echo "after validate <br>";
|
||||||
|
|
||||||
if ($transaction->save()) {
|
if ($transaction->save()) {
|
||||||
|
|
||||||
|
|
||||||
// success
|
// success
|
||||||
return $this->returnJson(['state' => 'success']);
|
return $this->returnJson(['state' => 'success']);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
$this->sendEMailTransactionFailed($transaction, 'save');
|
||||||
return $this->returnJsonSaveError($transaction, [
|
return $this->returnJsonSaveError($transaction, [
|
||||||
'state' => 'error',
|
'state' => 'error',
|
||||||
'msg' => 'error saving transaction in db',
|
'msg' => 'error saving transaction in db',
|
||||||
'details' => json_encode($transaction->getErrors())
|
'details' => json_encode($transaction->getErrors())
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->returnJson(['state' => 'success']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function moveTransaction($pubkeys, $memo, $session_id) {
|
private function moveTransaction($pubkeys, $memo, $session_id) {
|
||||||
|
|||||||
168
community_server/src/Controller/MigrationsController.php
Normal file
168
community_server/src/Controller/MigrationsController.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Controller\AppController;
|
||||||
|
use Cake\ORM\TableRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrations Controller
|
||||||
|
*
|
||||||
|
* @property \App\Model\Table\MigrationsTable $Migrations
|
||||||
|
*
|
||||||
|
* @method \App\Model\Entity\Migration[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
|
||||||
|
*/
|
||||||
|
class MigrationsController extends AppController
|
||||||
|
{
|
||||||
|
public function initialize()
|
||||||
|
{
|
||||||
|
parent::initialize();
|
||||||
|
$this->Auth->allow('migrate');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index method
|
||||||
|
*
|
||||||
|
* @return \Cake\Http\Response|null
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$migrations = $this->paginate($this->Migrations);
|
||||||
|
|
||||||
|
$this->set(compact('migrations'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function callFunctions(array $callables)
|
||||||
|
{
|
||||||
|
foreach($callables as $callable) {
|
||||||
|
$result = call_user_func($callable);
|
||||||
|
if(!$result['success']) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ['success' => true];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function migrate()
|
||||||
|
{
|
||||||
|
|
||||||
|
$html = $this->request->getQuery('html');
|
||||||
|
$current_db_version = $this->request->getQuery('db_version');
|
||||||
|
|
||||||
|
$startTime = microtime(true);
|
||||||
|
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||||
|
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||||
|
$transactionTypesTable = TableRegistry::getTableLocator()->get('TransactionTypes');
|
||||||
|
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||||
|
$blockchainTypesTable = TableRegistry::getTableLocator()->get('BlockchainTypes');
|
||||||
|
|
||||||
|
$new_db_version = 1;
|
||||||
|
|
||||||
|
$commands = [];
|
||||||
|
// migrate from version 1 to 2
|
||||||
|
if($current_db_version == 1) {
|
||||||
|
$stateUserTransactionsTable->truncate();
|
||||||
|
$commands = [
|
||||||
|
[$blockchainTypesTable, 'fillWithDefault'],
|
||||||
|
[$transactionTypesTable, 'fillWithDefault'],
|
||||||
|
[$stateBalancesTable, 'truncate'],
|
||||||
|
[$transactionsTable, 'fillStateUserTransactions'],
|
||||||
|
[$stateBalancesTable, 'updateAllBalances']
|
||||||
|
];
|
||||||
|
$new_db_version = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$migration_result = $this->callFunctions($commands);
|
||||||
|
if($migration_result['success']) {
|
||||||
|
$migration_entity = $this->Migrations->newEntity();
|
||||||
|
$migration_entity->db_version = $new_db_version;
|
||||||
|
$this->Migrations->save($migration_entity);
|
||||||
|
}
|
||||||
|
if(!$html) {
|
||||||
|
return $this->returnJson($migration_result);
|
||||||
|
} else {
|
||||||
|
$this->set('db_version', $current_db_version);
|
||||||
|
$this->set('result', $migration_result);
|
||||||
|
$this->set('timeUsed', microtime(true) - $startTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View method
|
||||||
|
*
|
||||||
|
* @param string|null $id Migration id.
|
||||||
|
* @return \Cake\Http\Response|null
|
||||||
|
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
|
||||||
|
*/
|
||||||
|
public function view($id = null)
|
||||||
|
{
|
||||||
|
$migration = $this->Migrations->get($id, [
|
||||||
|
'contain' => [],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->set('migration', $migration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add method
|
||||||
|
*
|
||||||
|
* @return \Cake\Http\Response|null Redirects on successful add, renders view otherwise.
|
||||||
|
*/
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
$migration = $this->Migrations->newEntity();
|
||||||
|
if ($this->request->is('post')) {
|
||||||
|
$migration = $this->Migrations->patchEntity($migration, $this->request->getData());
|
||||||
|
if ($this->Migrations->save($migration)) {
|
||||||
|
$this->Flash->success(__('The migration has been saved.'));
|
||||||
|
|
||||||
|
return $this->redirect(['action' => 'index']);
|
||||||
|
}
|
||||||
|
$this->Flash->error(__('The migration could not be saved. Please, try again.'));
|
||||||
|
}
|
||||||
|
$this->set(compact('migration'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit method
|
||||||
|
*
|
||||||
|
* @param string|null $id Migration id.
|
||||||
|
* @return \Cake\Http\Response|null Redirects on successful edit, renders view otherwise.
|
||||||
|
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
|
||||||
|
*/
|
||||||
|
public function edit($id = null)
|
||||||
|
{
|
||||||
|
$migration = $this->Migrations->get($id, [
|
||||||
|
'contain' => [],
|
||||||
|
]);
|
||||||
|
if ($this->request->is(['patch', 'post', 'put'])) {
|
||||||
|
$migration = $this->Migrations->patchEntity($migration, $this->request->getData());
|
||||||
|
if ($this->Migrations->save($migration)) {
|
||||||
|
$this->Flash->success(__('The migration has been saved.'));
|
||||||
|
|
||||||
|
return $this->redirect(['action' => 'index']);
|
||||||
|
}
|
||||||
|
$this->Flash->error(__('The migration could not be saved. Please, try again.'));
|
||||||
|
}
|
||||||
|
$this->set(compact('migration'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete method
|
||||||
|
*
|
||||||
|
* @param string|null $id Migration id.
|
||||||
|
* @return \Cake\Http\Response|null Redirects to index.
|
||||||
|
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
|
||||||
|
*/
|
||||||
|
public function delete($id = null)
|
||||||
|
{
|
||||||
|
$this->request->allowMethod(['post', 'delete']);
|
||||||
|
$migration = $this->Migrations->get($id);
|
||||||
|
if ($this->Migrations->delete($migration)) {
|
||||||
|
$this->Flash->success(__('The migration has been deleted.'));
|
||||||
|
} else {
|
||||||
|
$this->Flash->error(__('The migration could not be deleted. Please, try again.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirect(['action' => 'index']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use Cake\ORM\TableRegistry;
|
use Cake\ORM\TableRegistry;
|
||||||
use Cake\I18n\Time;
|
use Cake\I18n\FrozenTime;
|
||||||
|
|
||||||
use Model\Navigation\NaviHierarchy;
|
use Model\Navigation\NaviHierarchy;
|
||||||
use Model\Navigation\NaviHierarchyEntry;
|
use Model\Navigation\NaviHierarchyEntry;
|
||||||
@ -62,9 +62,10 @@ class StateBalancesController extends AppController
|
|||||||
|
|
||||||
$user = $session->read('StateUser');
|
$user = $session->read('StateUser');
|
||||||
$update_balance_result = $this->StateBalances->updateBalances($user['id']);
|
$update_balance_result = $this->StateBalances->updateBalances($user['id']);
|
||||||
if($update_balance_result !== true) {
|
if($update_balance_result['success'] !== true) {
|
||||||
$this->addAdminError('StateBalances', 'overview', $update_balance_result, $user['id']);
|
$this->addAdminError('StateBalances', 'overview', $update_balance_result, $user['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendRequestGDT
|
// sendRequestGDT
|
||||||
// listPerEmailApi
|
// listPerEmailApi
|
||||||
|
|
||||||
@ -84,200 +85,68 @@ class StateBalancesController extends AppController
|
|||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||||
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||||
|
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||||
|
|
||||||
$creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
|
|
||||||
$creationTransactions = $creationsTable
|
|
||||||
->find('all')
|
|
||||||
->where(['state_user_id' => $user['id']])
|
|
||||||
->contain(['Transactions']);
|
|
||||||
|
|
||||||
$transferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
|
$stateBalancesTable->updateBalances($user['id']);
|
||||||
$transferTransactions = $transferTable
|
|
||||||
->find('all')
|
|
||||||
->where(['OR' => ['state_user_id' => $user['id'], 'receiver_user_id' => $user['id']]])
|
|
||||||
->contain(['Transactions']);
|
|
||||||
|
|
||||||
$involvedUserIds = [];
|
$gdtSum = 0;
|
||||||
|
$gdtEntries = $this->JsonRequestClient->sendRequestGDT(['email' => $user['email']], 'GdtEntries' . DS . 'sumPerEmailApi');
|
||||||
|
|
||||||
foreach ($transferTransactions as $sendCoins) {
|
if('success' == $gdtEntries['state'] && 'success' == $gdtEntries['data']['state']) {
|
||||||
//var_dump($sendCoins);
|
$gdtSum = intval($gdtEntries['data']['sum']);
|
||||||
if ($sendCoins->state_user_id != $user['id']) {
|
} else {
|
||||||
array_push($involvedUserIds, intval($sendCoins->state_user_id));
|
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id'] ? $user['id'] : 0);
|
||||||
} elseif ($sendCoins->receiver_user_id != $user['id']) {
|
|
||||||
array_push($involvedUserIds, intval($sendCoins->receiver_user_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*echo "state user from sendCoins: $sendCoins->state_user_id<br>";
|
|
||||||
echo "receiver user from sendCoins: $sendCoins->receiver_user_id<br>";
|
|
||||||
echo "user id from logged in user: ".$user['id']. '<br>';
|
|
||||||
*/
|
|
||||||
//var_dump($involvedUserIds);
|
|
||||||
// exchange key with values and drop duplicates
|
|
||||||
$involvedUser_temp = array_flip($involvedUserIds);
|
|
||||||
// exchange back
|
|
||||||
$involvedUserIds = array_flip($involvedUser_temp);
|
|
||||||
$userTable = TableRegistry::getTableLocator()->get('StateUsers');
|
|
||||||
$involvedUser = $userTable->find('all', [
|
|
||||||
'contain' => false,
|
|
||||||
'where' => ['id IN' => $involvedUserIds],
|
|
||||||
'fields' => ['id', 'first_name', 'last_name', 'email']
|
|
||||||
]);
|
|
||||||
//var_dump($involvedUser->toArray());
|
|
||||||
$involvedUserIndices = [];
|
|
||||||
foreach ($involvedUser as $involvedUser) {
|
|
||||||
$involvedUserIndices[$involvedUser->id] = $involvedUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sender or receiver when user has sended money
|
|
||||||
// group name if creation
|
|
||||||
// type: gesendet / empfangen / geschöpft
|
|
||||||
// transaktion nr / id
|
|
||||||
// date
|
|
||||||
// balance
|
|
||||||
|
|
||||||
|
$stateUserTransactionsQuery = $stateUserTransactionsTable
|
||||||
|
->find()
|
||||||
|
->where(['state_user_id' => $user['id']])
|
||||||
|
->order(['balance_date' => 'ASC'])
|
||||||
|
->contain([])
|
||||||
|
;
|
||||||
|
$decay = true;
|
||||||
$transactions = [];
|
$transactions = [];
|
||||||
foreach ($creationTransactions as $creation) {
|
if($stateUserTransactionsQuery->count() > 0) {
|
||||||
//var_dump($creation);
|
$transactions = $transactionsTable->listTransactionsHumanReadable($stateUserTransactionsQuery->toArray(), $user, $decay);
|
||||||
array_push($transactions, [
|
|
||||||
'name' => 'Gradido Akademie',
|
|
||||||
'type' => 'creation',
|
|
||||||
'transaction_id' => $creation->transaction_id,
|
|
||||||
'date' => $creation->target_date,
|
|
||||||
'balance' => $creation->amount,
|
|
||||||
'memo' => $creation->transaction->memo
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($transferTransactions as $sendCoins) {
|
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $user['id']])->first();
|
||||||
$type = '';
|
|
||||||
$otherUser = null;
|
|
||||||
$other_user_public = '';
|
|
||||||
if ($sendCoins->state_user_id == $user['id']) {
|
|
||||||
$type = 'send';
|
|
||||||
|
|
||||||
if(isset($involvedUserIndices[$sendCoins->receiver_user_id])) {
|
$body = [
|
||||||
$otherUser = $involvedUserIndices[$sendCoins->receiver_user_id];
|
'state' => 'success',
|
||||||
}
|
'transactions' => $transactions,
|
||||||
$other_user_public = bin2hex(stream_get_contents($sendCoins->receiver_public_key));
|
'transactionExecutingCount' => $session->read('Transactions.executing'),
|
||||||
} else if ($sendCoins->receiver_user_id == $user['id']) {
|
'count' => count($transactions),
|
||||||
$type = 'receive';
|
'gdtSum' => $gdtSum,
|
||||||
if(isset($involvedUserIndices[$sendCoins->state_user_id])) {
|
'timeUsed' => microtime(true) - $startTime
|
||||||
$otherUser = $involvedUserIndices[$sendCoins->state_user_id];
|
];
|
||||||
}
|
$now = new FrozenTime();
|
||||||
if($sendCoins->sender_public_key) {
|
$body['decay_date'] = $now;
|
||||||
$other_user_public = bin2hex(stream_get_contents($sendCoins->sender_public_key));
|
|
||||||
}
|
if(!$state_balance) {
|
||||||
}
|
$balance = 0.0;
|
||||||
if(null == $otherUser) {
|
} else {
|
||||||
$otherUser = $this->StateBalances->StateUsers->newEntity();
|
$balance = $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now);
|
||||||
}
|
//$balance = $state_balance->partDecay($now);
|
||||||
array_push($transactions, [
|
|
||||||
'name' => $otherUser->first_name . ' ' . $otherUser->last_name,
|
|
||||||
'email' => $otherUser->email,
|
|
||||||
'type' => $type,
|
|
||||||
'transaction_id' => $sendCoins->transaction_id,
|
|
||||||
'date' => $sendCoins->transaction->received,
|
|
||||||
'balance' => $sendCoins->amount,
|
|
||||||
'memo' => $sendCoins->transaction->memo,
|
|
||||||
'pubkey' => $other_user_public
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
uasort($transactions, array($this, 'sortTransactions'));
|
|
||||||
|
|
||||||
// add decay transactions
|
|
||||||
$month_start_state_balance = null;
|
|
||||||
$current_state_balance = null;
|
|
||||||
$cursor = 0;
|
|
||||||
$transactions_reversed = array_reverse($transactions);
|
|
||||||
$decay_transactions = [];
|
|
||||||
$maxI = count($transactions_reversed);
|
|
||||||
|
|
||||||
foreach($transactions_reversed as $i => $transaction) {
|
|
||||||
if(!isset($transaction['transaction_id'])) {
|
|
||||||
//echo "missing transaction<br>";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$transaction_id = $transaction['transaction_id'];
|
|
||||||
//echo "transaction id: $transaction_id <br>";
|
|
||||||
$decay_transaction = NULL;
|
|
||||||
$state_balance = $this->StateBalances->newEntity();
|
|
||||||
|
|
||||||
if($i > 0 && isset($transactions_reversed[$i-1]['transaction_id'])) {
|
|
||||||
$prev_transaction = $transactions_reversed[$i-1];
|
|
||||||
$stateUserTransactions = $stateUserTransactionsTable
|
|
||||||
->find()
|
|
||||||
->where([
|
|
||||||
'transaction_id IN' => [$transaction_id, $prev_transaction['transaction_id']],
|
|
||||||
'state_user_id' => $user['id']
|
|
||||||
])
|
|
||||||
->order(['balance_date ASC'])
|
|
||||||
->toArray();
|
|
||||||
|
|
||||||
$prev = $stateUserTransactions[0];
|
|
||||||
if($prev->balance > 0) {
|
|
||||||
// var_dump($stateUserTransactions);
|
|
||||||
$current = $stateUserTransactions[1];
|
|
||||||
//echo "decay between " . $prev->transaction_id . " and " . $current->transaction_id . "<br>";
|
|
||||||
$interval = $current->balance_date->diff($prev->balance_date);
|
|
||||||
$state_balance->amount = $prev->balance;
|
|
||||||
$state_balance->record_date = $prev->balance_date;
|
|
||||||
$diff_amount = $state_balance->partDecay($current->balance_date);
|
|
||||||
|
|
||||||
//echo $interval->format('%R%a days');
|
|
||||||
//echo "prev balance: " . $prev->balance . ", diff_amount: $diff_amount, summe: " . (-intval($prev->balance - $diff_amount)) . "<br>";
|
|
||||||
$decay_transaction = [
|
|
||||||
'type' => 'decay',
|
|
||||||
'balance' => -intval($prev->balance - $diff_amount),
|
|
||||||
'decay_duration' => $interval->format('%a days, %H hours, %I minutes, %S seconds'),
|
|
||||||
'memo' => ''
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($decay_transaction) {
|
|
||||||
$decay_transactions[] = $decay_transaction;
|
|
||||||
//array_splice($transactions_reversed, $i + $cursor, 0, [$decay_transaction]);
|
|
||||||
//$cursor++;
|
|
||||||
}
|
|
||||||
if($i == $maxI-1) {
|
|
||||||
$stateUserTransaction = $stateUserTransactionsTable
|
|
||||||
->find()
|
|
||||||
->where(['transaction_id' => $transaction_id, 'state_user_id' => $user['id']])
|
|
||||||
->order(['transaction_id ASC'])->first();
|
|
||||||
//var_dump($stateUserTransaction);
|
|
||||||
$state_balance->amount = $stateUserTransaction->balance;
|
|
||||||
$state_balance->record_date = $stateUserTransaction->balance_date;
|
|
||||||
$decay_transactions[] = [
|
|
||||||
//$transactions_reversed[] = [
|
|
||||||
'type' => 'decay',
|
|
||||||
'balance' => -intval($stateUserTransaction->balance - $state_balance->decay),
|
|
||||||
'decay_duration' => $stateUserTransaction->balance_date->timeAgoInWords(),
|
|
||||||
'memo' => ''
|
|
||||||
];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$final_transactions = [];
|
|
||||||
foreach($transactions_reversed as $i => $transaction) {
|
|
||||||
$final_transactions[] = $transaction;
|
|
||||||
$final_transactions[] = $decay_transactions[$i];
|
|
||||||
}
|
|
||||||
// for debugging
|
|
||||||
$calculated_balance = 0;
|
$calculated_balance = 0;
|
||||||
foreach($final_transactions as $tr) {
|
foreach($transactions as $transaction) {
|
||||||
if($tr['type'] == 'send') {
|
if($transaction['type'] == 'decay' || $transaction['type'] == 'send') {
|
||||||
$calculated_balance -= intval($tr['balance']);
|
$calculated_balance -= $transaction['balance'];
|
||||||
} else {
|
} else {
|
||||||
$calculated_balance += intval($tr['balance']);
|
$calculated_balance += $transaction['balance'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->set('calculated_balance', $calculated_balance);
|
$this->set('calculated_balance', $calculated_balance);
|
||||||
|
|
||||||
$this->set('transactions', array_reverse($final_transactions));
|
$this->set('transactions', array_reverse($transactions));
|
||||||
$this->set('transactionExecutingCount', $session->read('Transactions.executing'));
|
$this->set('transactionExecutingCount', $session->read('Transactions.executing'));
|
||||||
$this->set('balance', $session->read('StateUser.balance'));
|
$this->set('balance', $balance);
|
||||||
$this->set('timeUsed', microtime(true) - $startTime);
|
$this->set('timeUsed', microtime(true) - $startTime);
|
||||||
$this->set('gdtSum', $gdtSum);
|
$this->set('gdtSum', $gdtSum);
|
||||||
}
|
}
|
||||||
@ -301,152 +170,17 @@ class StateBalancesController extends AppController
|
|||||||
if(!$state_balance) {
|
if(!$state_balance) {
|
||||||
return $this->returnJson(['state' => 'success', 'balance' => 0]);
|
return $this->returnJson(['state' => 'success', 'balance' => 0]);
|
||||||
}
|
}
|
||||||
|
$now = new FrozenTime();
|
||||||
|
|
||||||
return $this->returnJson([
|
return $this->returnJson([
|
||||||
'state' => 'success',
|
'state' => 'success',
|
||||||
'balance' => $state_balance->amount,
|
'balance' => $state_balance->amount,
|
||||||
'decay' => $state_balance->decay
|
'decay' => $this->StateBalances->calculateDecay($state_balance->amount, $state_balance->record_date, $now),
|
||||||
|
'decay_date' => $now
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function ajaxListTransactions($session_id, $page=1, $count=25)
|
|
||||||
{
|
|
||||||
if(!$session_id) {
|
|
||||||
return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$startTime = microtime(true);
|
|
||||||
$login_result = $this->requestLogin($session_id, false);
|
|
||||||
if($login_result !== true) {
|
|
||||||
return $this->returnJson($login_result);
|
|
||||||
}
|
|
||||||
$session = $this->getRequest()->getSession();
|
|
||||||
$user = $session->read('StateUser');
|
|
||||||
|
|
||||||
$this->StateBalances->updateBalances($user['id']);
|
|
||||||
|
|
||||||
$gdtSum = 0;
|
|
||||||
$gdtEntries = $this->JsonRequestClient->sendRequestGDT(['email' => $user['email']], 'GdtEntries' . DS . 'sumPerEmailApi');
|
|
||||||
|
|
||||||
if('success' == $gdtEntries['state'] && 'success' == $gdtEntries['data']['state']) {
|
|
||||||
$gdtSum = intval($gdtEntries['data']['sum']);
|
|
||||||
} else {
|
|
||||||
if($user) {
|
|
||||||
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id']);
|
|
||||||
} else {
|
|
||||||
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
|
|
||||||
$creationTransactions = $creationsTable
|
|
||||||
->find('all')
|
|
||||||
->where(['state_user_id' => $user['id']])
|
|
||||||
->contain(['Transactions']);
|
|
||||||
|
|
||||||
$transferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
|
|
||||||
$transferTransactions = $transferTable
|
|
||||||
->find('all')
|
|
||||||
->where(['OR' => ['state_user_id' => $user['id'], 'receiver_user_id' => $user['id']]])
|
|
||||||
->contain(['Transactions']);
|
|
||||||
|
|
||||||
$involvedUserIds = [];
|
|
||||||
|
|
||||||
foreach ($transferTransactions as $sendCoins) {
|
|
||||||
//var_dump($sendCoins);
|
|
||||||
if ($sendCoins->state_user_id != $user['id']) {
|
|
||||||
array_push($involvedUserIds, intval($sendCoins->state_user_id));
|
|
||||||
} elseif ($sendCoins->receiver_user_id != $user['id']) {
|
|
||||||
array_push($involvedUserIds, intval($sendCoins->receiver_user_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*echo "state user from sendCoins: $sendCoins->state_user_id<br>";
|
|
||||||
echo "receiver user from sendCoins: $sendCoins->receiver_user_id<br>";
|
|
||||||
echo "user id from logged in user: ".$user['id']. '<br>';
|
|
||||||
*/
|
|
||||||
//var_dump($involvedUserIds);
|
|
||||||
// exchange key with values and drop duplicates
|
|
||||||
$involvedUser_temp = array_flip($involvedUserIds);
|
|
||||||
// exchange back
|
|
||||||
$involvedUserIds = array_flip($involvedUser_temp);
|
|
||||||
$userTable = TableRegistry::getTableLocator()->get('StateUsers');
|
|
||||||
$involvedUser = $userTable->find('all', [
|
|
||||||
'contain' => false,
|
|
||||||
'where' => ['id IN' => $involvedUserIds],
|
|
||||||
'fields' => ['id', 'first_name', 'last_name', 'email']
|
|
||||||
]);
|
|
||||||
//var_dump($involvedUser->toArray());
|
|
||||||
$involvedUserIndices = [];
|
|
||||||
foreach ($involvedUser as $involvedUser) {
|
|
||||||
$involvedUserIndices[$involvedUser->id] = $involvedUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sender or receiver when user has sended money
|
|
||||||
// group name if creation
|
|
||||||
// type: gesendet / empfangen / geschöpft
|
|
||||||
// transaktion nr / id
|
|
||||||
// date
|
|
||||||
// balance
|
|
||||||
|
|
||||||
$transactions = [];
|
|
||||||
foreach ($creationTransactions as $creation) {
|
|
||||||
//var_dump($creation);
|
|
||||||
array_push($transactions, [
|
|
||||||
'name' => 'Gradido Akademie',
|
|
||||||
'type' => 'creation',
|
|
||||||
'transaction_id' => $creation->transaction_id,
|
|
||||||
'date' => $creation->transaction->received,
|
|
||||||
'balance' => $creation->amount,
|
|
||||||
'memo' => $creation->transaction->memo
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($transferTransactions as $sendCoins) {
|
|
||||||
$type = '';
|
|
||||||
$otherUser = null;
|
|
||||||
if ($sendCoins->state_user_id == $user['id']) {
|
|
||||||
$type = 'send';
|
|
||||||
|
|
||||||
if(isset($involvedUserIndices[$sendCoins->receiver_user_id])) {
|
|
||||||
$otherUser = $involvedUserIndices[$sendCoins->receiver_user_id];
|
|
||||||
}
|
|
||||||
} else if ($sendCoins->receiver_user_id == $user['id']) {
|
|
||||||
$type = 'receive';
|
|
||||||
if(isset($involvedUserIndices[$sendCoins->state_user_id])) {
|
|
||||||
$otherUser = $involvedUserIndices[$sendCoins->state_user_id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(null == $otherUser) {
|
|
||||||
$otherUser = $this->StateBalances->StateUsers->newEntity();
|
|
||||||
}
|
|
||||||
array_push($transactions, [
|
|
||||||
'name' => $otherUser->first_name . ' ' . $otherUser->last_name,
|
|
||||||
'email' => $otherUser->email,
|
|
||||||
'type' => $type,
|
|
||||||
'transaction_id' => $sendCoins->transaction_id,
|
|
||||||
'date' => $sendCoins->transaction->received,
|
|
||||||
'balance' => $sendCoins->amount,
|
|
||||||
'memo' => $sendCoins->transaction->memo
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
uasort($transactions, array($this, 'sortTransactions'));
|
|
||||||
if($sort == 'DESC') {
|
|
||||||
$transactions = array_reverse($transactions);
|
|
||||||
}
|
|
||||||
return $this->returnJson([
|
|
||||||
'state' => 'success',
|
|
||||||
'transactions' => $transactions,
|
|
||||||
'transactionExecutingCount' => $session->read('Transactions.executing'),
|
|
||||||
'count' => count($transactions),
|
|
||||||
'gdtSum' => $gdtSum,
|
|
||||||
'timeUsed' => microtime(true) - $startTime
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function ajaxGdtOverview()
|
public function ajaxGdtOverview()
|
||||||
{
|
{
|
||||||
$gdtSum = 0;
|
$gdtSum = 0;
|
||||||
|
|||||||
@ -237,6 +237,11 @@ class TransactionSendCoinsController extends AppController
|
|||||||
$this->set('timeUsed', microtime(true) - $startTime);
|
$this->set('timeUsed', microtime(true) - $startTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if($answear_data['msg'] === 'memo is not set or not in expected range [5;150]') {
|
||||||
|
$this->Flash->error(__('Ein Verwendungszweck zwischen 5 und 150 Zeichen wird benötig!'));
|
||||||
|
$this->set('timeUsed', microtime(true) - $startTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else if($answear_data['state'] === 'not found' && $answear_data['msg'] === 'receiver not found') {
|
} else if($answear_data['state'] === 'not found' && $answear_data['msg'] === 'receiver not found') {
|
||||||
$this->Flash->error(__('Der Empfänger wurde nicht auf dem Login-Server gefunden, hat er sein Konto schon angelegt?'));
|
$this->Flash->error(__('Der Empfänger wurde nicht auf dem Login-Server gefunden, hat er sein Konto schon angelegt?'));
|
||||||
$this->set('timeUsed', microtime(true) - $startTime);
|
$this->set('timeUsed', microtime(true) - $startTime);
|
||||||
|
|||||||
@ -313,15 +313,20 @@ class TransactionsController extends AppController
|
|||||||
if ($this->request->is('post')) {
|
if ($this->request->is('post')) {
|
||||||
$transaction = $this->Transactions->patchEntity($transaction, $this->request->getData());
|
$transaction = $this->Transactions->patchEntity($transaction, $this->request->getData());
|
||||||
if ($this->Transactions->save($transaction)) {
|
if ($this->Transactions->save($transaction)) {
|
||||||
$this->Flash->success(__('The transaction has been saved.'));
|
$result = $this->Transactions->updateTxHash($transaction, 'start decay');
|
||||||
|
if($result === true) {
|
||||||
return $this->redirect(['action' => 'index']);
|
$this->Flash->success(__('The transaction has been saved.'));
|
||||||
|
return $this->redirect(['action' => 'index']);
|
||||||
|
} else {
|
||||||
|
$this->Flash->error(__('Error by saving: ' . json_encode($result)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$this->Flash->error(__('The transaction could not be saved. Please, try again.'));
|
$this->Flash->error(__('The transaction could not be saved. Please, try again.'));
|
||||||
}
|
}
|
||||||
$stateGroups = $this->Transactions->StateGroups->find('list', ['limit' => 200]);
|
$stateGroups = $this->Transactions->StateGroups->find('list', ['limit' => 200]);
|
||||||
$transactionTypes = $this->Transactions->TransactionTypes->find('list', ['limit' => 200]);
|
$transactionTypes = $this->Transactions->TransactionTypes->find('list', ['limit' => 200]);
|
||||||
$this->set(compact('transaction', 'stateGroups', 'transactionTypes'));
|
$blockchainTypes = $this->Transactions->BlockchainTypes->find('list');
|
||||||
|
$this->set(compact('transaction', 'stateGroups', 'transactionTypes', 'blockchainTypes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
26
community_server/src/Model/Entity/Migration.php
Normal file
26
community_server/src/Model/Entity/Migration.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Model\Entity;
|
||||||
|
|
||||||
|
use Cake\ORM\Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration Entity
|
||||||
|
*
|
||||||
|
* @property int $id
|
||||||
|
* @property int|null $db_version
|
||||||
|
*/
|
||||||
|
class Migration extends Entity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fields that can be mass assigned using newEntity() or patchEntity().
|
||||||
|
*
|
||||||
|
* Note that when '*' is set to true, this allows all unspecified fields to
|
||||||
|
* be mass assigned. For security purposes, it is advised to set '*' to false
|
||||||
|
* (or remove it), and explicitly make individual fields accessible as needed.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_accessible = [
|
||||||
|
'db_version' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -44,9 +44,7 @@ class StateBalance extends Entity
|
|||||||
} else if(method_exists($dateOrTime, 'i18nFormat')) {
|
} else if(method_exists($dateOrTime, 'i18nFormat')) {
|
||||||
return $dateOrTime->i18nFormat(Time::UNIX_TIMESTAMP_FORMAT);
|
return $dateOrTime->i18nFormat(Time::UNIX_TIMESTAMP_FORMAT);
|
||||||
} else {
|
} else {
|
||||||
var_dump($dateOrTime);
|
return 0;
|
||||||
debug_print_backtrace(0, 6);
|
|
||||||
die("date or time unexpected object");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +57,12 @@ class StateBalance extends Entity
|
|||||||
// SELECT TIMESTAMPDIFF(SECOND, modified, CURDATE()) AS age_in_seconds from state_balances
|
// SELECT TIMESTAMPDIFF(SECOND, modified, CURDATE()) AS age_in_seconds from state_balances
|
||||||
// decay_for_duration = decay_factor^seconds
|
// decay_for_duration = decay_factor^seconds
|
||||||
// decay = gradido_cent * decay_for_duration
|
// decay = gradido_cent * decay_for_duration
|
||||||
|
$startDate = $this->convertToTimestamp($this->record_date);
|
||||||
|
if($startDate == 0) {
|
||||||
|
return $this->amount;
|
||||||
|
}
|
||||||
|
|
||||||
$decay_duration = intval(Time::now()->getTimestamp() - $this->convertToTimestamp($this->record_date));
|
$decay_duration = intval(Time::now()->getTimestamp() - $startDate);
|
||||||
if($decay_duration === 0) {
|
if($decay_duration === 0) {
|
||||||
return $this->amount;
|
return $this->amount;
|
||||||
}
|
}
|
||||||
|
|||||||
41
community_server/src/Model/Table/AppTable.php
Normal file
41
community_server/src/Model/Table/AppTable.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Model\Table;
|
||||||
|
|
||||||
|
use Cake\ORM\Table;
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
class AppTable extends Table
|
||||||
|
{
|
||||||
|
|
||||||
|
public function initialize(array $config)
|
||||||
|
{
|
||||||
|
parent::initialize($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function truncate()
|
||||||
|
{
|
||||||
|
$truncateCommands = $this->getSchema()->truncateSql($this->getConnection());
|
||||||
|
foreach ($truncateCommands as $truncateCommand) {
|
||||||
|
$this->getConnection()->query($truncateCommand);
|
||||||
|
}
|
||||||
|
$this->getConnection()->query('ALTER TABLE ' . $this->getSchema()->name() . ' AUTO_INCREMENT=1');
|
||||||
|
return ['success' => true];
|
||||||
|
}
|
||||||
|
public function saveManyWithErrors($entities)
|
||||||
|
{
|
||||||
|
$save_results = $this->saveMany($entities);
|
||||||
|
// save all at once failed, no try one by one to get error message
|
||||||
|
if($save_results === false) {
|
||||||
|
foreach($entities as $entity) {
|
||||||
|
if(!$this->save($entity)) {
|
||||||
|
return ['success' => false, 'errors' => $entity->getErrors()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ['success' => true];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,7 +18,7 @@ use Cake\Validation\Validator;
|
|||||||
* @method \App\Model\Entity\BlockchainType[] patchEntities($entities, array $data, array $options = [])
|
* @method \App\Model\Entity\BlockchainType[] patchEntities($entities, array $data, array $options = [])
|
||||||
* @method \App\Model\Entity\BlockchainType findOrCreate($search, callable $callback = null, $options = [])
|
* @method \App\Model\Entity\BlockchainType findOrCreate($search, callable $callback = null, $options = [])
|
||||||
*/
|
*/
|
||||||
class BlockchainTypesTable extends Table
|
class BlockchainTypesTable extends AppTable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initialize method
|
* Initialize method
|
||||||
@ -65,4 +65,30 @@ class BlockchainTypesTable extends Table
|
|||||||
|
|
||||||
return $validator;
|
return $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fillWithDefault()
|
||||||
|
{
|
||||||
|
$entry_contents = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'name' => 'mysql',
|
||||||
|
'text' => 'use mysql db as blockchain, work only with single community-server',
|
||||||
|
'symbol' => NULL
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 2,
|
||||||
|
'name' => 'hedera',
|
||||||
|
'text' => 'use hedera for transactions',
|
||||||
|
'symbol' => 'HBAR'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$entities = $this->newEntities($entry_contents);
|
||||||
|
$this->truncate();
|
||||||
|
$save_results = $this->saveManyWithErrors($entities);
|
||||||
|
if(!$save_results['success']) {
|
||||||
|
$save_results['msg'] = 'error by saving default transaction types';
|
||||||
|
}
|
||||||
|
return $save_results;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
community_server/src/Model/Table/MigrationsTable.php
Normal file
56
community_server/src/Model/Table/MigrationsTable.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Model\Table;
|
||||||
|
|
||||||
|
use Cake\ORM\Query;
|
||||||
|
use Cake\ORM\RulesChecker;
|
||||||
|
use Cake\ORM\Table;
|
||||||
|
use Cake\Validation\Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrations Model
|
||||||
|
*
|
||||||
|
* @method \App\Model\Entity\Migration get($primaryKey, $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration newEntity($data = null, array $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration[] newEntities(array $data, array $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration|false save(\Cake\Datasource\EntityInterface $entity, $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration[] patchEntities($entities, array $data, array $options = [])
|
||||||
|
* @method \App\Model\Entity\Migration findOrCreate($search, callable $callback = null, $options = [])
|
||||||
|
*/
|
||||||
|
class MigrationsTable extends Table
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize method
|
||||||
|
*
|
||||||
|
* @param array $config The configuration for the Table.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function initialize(array $config)
|
||||||
|
{
|
||||||
|
parent::initialize($config);
|
||||||
|
|
||||||
|
$this->setTable('migrations');
|
||||||
|
$this->setDisplayField('id');
|
||||||
|
$this->setPrimaryKey('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default validation rules.
|
||||||
|
*
|
||||||
|
* @param \Cake\Validation\Validator $validator Validator instance.
|
||||||
|
* @return \Cake\Validation\Validator
|
||||||
|
*/
|
||||||
|
public function validationDefault(Validator $validator)
|
||||||
|
{
|
||||||
|
$validator
|
||||||
|
->nonNegativeInteger('id')
|
||||||
|
->allowEmptyString('id', null, 'create');
|
||||||
|
|
||||||
|
$validator
|
||||||
|
->integer('db_version')
|
||||||
|
->allowEmptyString('db_version');
|
||||||
|
|
||||||
|
return $validator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace App\Model\Table;
|
namespace App\Model\Table;
|
||||||
|
|
||||||
use Cake\ORM\Query;
|
|
||||||
use Cake\ORM\RulesChecker;
|
use Cake\ORM\RulesChecker;
|
||||||
use Cake\ORM\Table;
|
use Cake\ORM\Table;
|
||||||
use Cake\Validation\Validator;
|
use Cake\Validation\Validator;
|
||||||
|
|
||||||
use Cake\ORM\TableRegistry;
|
use Cake\ORM\TableRegistry;
|
||||||
use Cake\I18n\Date;
|
use Cake\I18n\FrozenTime;
|
||||||
use Cake\I18n\Time;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StateBalances Model
|
* StateBalances Model
|
||||||
@ -26,8 +24,9 @@ use Cake\I18n\Time;
|
|||||||
*
|
*
|
||||||
* @mixin \Cake\ORM\Behavior\TimestampBehavior
|
* @mixin \Cake\ORM\Behavior\TimestampBehavior
|
||||||
*/
|
*/
|
||||||
class StateBalancesTable extends Table
|
class StateBalancesTable extends AppTable
|
||||||
{
|
{
|
||||||
|
private static $startDecayDate = null;
|
||||||
/**
|
/**
|
||||||
* Initialize method
|
* Initialize method
|
||||||
*
|
*
|
||||||
@ -50,6 +49,15 @@ class StateBalancesTable extends Table
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getDecayStartDateCached()
|
||||||
|
{
|
||||||
|
if(self::$startDecayDate == null) {
|
||||||
|
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||||
|
self::$startDecayDate = $transactionsTable->getDecayStartDate();
|
||||||
|
}
|
||||||
|
return self::$startDecayDate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default validation rules.
|
* Default validation rules.
|
||||||
*
|
*
|
||||||
@ -83,20 +91,60 @@ class StateBalancesTable extends Table
|
|||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function calculateDecay($startBalance, FrozenTime $startDate, FrozenTime $endDate, $withInterval = false)
|
||||||
public function sortTransactions($a, $b)
|
|
||||||
{
|
{
|
||||||
if ($a['date'] == $b['date']) {
|
$decayStartDate = self::getDecayStartDateCached();
|
||||||
return 0;
|
// if no start decay block exist, we just return input
|
||||||
|
// if start date for decay is after enddate, we also just return input
|
||||||
|
if($decayStartDate === null || $decayStartDate >= $endDate) {
|
||||||
|
if($withInterval) {
|
||||||
|
return ['balance' => $startBalance, 'interval' => new \DateInterval('PT0S')];
|
||||||
|
} else {
|
||||||
|
return $startBalance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ($a['date'] > $b['date']) ? -1 : 1;
|
$state_balance = $this->newEntity();
|
||||||
|
$state_balance->amount = $startBalance;
|
||||||
|
$interval = null;
|
||||||
|
// if decay start date is before start date we calculate decay for full duration
|
||||||
|
if($decayStartDate < $startDate) {
|
||||||
|
$state_balance->record_date = $startDate;
|
||||||
|
$interval = $endDate->diff($startDate);
|
||||||
|
}
|
||||||
|
// if decay start in between start date and end date we caculcate decay from decay start time to end date
|
||||||
|
else {
|
||||||
|
$state_balance->record_date = $decayStartDate;
|
||||||
|
$interval = $endDate->diff($decayStartDate);
|
||||||
|
}
|
||||||
|
$decay = $state_balance->partDecay($endDate);
|
||||||
|
if($withInterval) {
|
||||||
|
return ['balance' => $decay, 'interval' => $interval];
|
||||||
|
} else {
|
||||||
|
return $decay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateAllBalances()
|
||||||
|
{
|
||||||
|
$stateUserTable = TableRegistry::getTableLocator()->get('StateUsers');
|
||||||
|
$state_users = $stateUserTable->find()->select(['id'])->contain([]);
|
||||||
|
foreach($state_users as $state_user) {
|
||||||
|
$result = $this->updateBalances($state_user->id);
|
||||||
|
if($result['success'] === false) {
|
||||||
|
$result['state_user_id'] = $state_user->id;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ['success' => true];
|
||||||
|
}
|
||||||
|
|
||||||
public function updateBalances($stateUserId)
|
public function updateBalances($stateUserId)
|
||||||
{
|
{
|
||||||
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||||
|
$now = new FrozenTime;
|
||||||
// info: cakephp use lazy loading, query will be executed later only if needed
|
// info: cakephp use lazy loading, query will be executed later only if needed
|
||||||
$state_balances = $this->find('all')->where(['state_user_id' => $stateUserId]);
|
$state_balances = $this->find('all')->where(['state_user_id' => $stateUserId]);
|
||||||
$state_user_transactions = $stateUserTransactionsTable
|
$state_user_transactions = $stateUserTransactionsTable
|
||||||
@ -107,7 +155,7 @@ class StateBalancesTable extends Table
|
|||||||
;
|
;
|
||||||
|
|
||||||
if(!$state_user_transactions || !$state_user_transactions->count()) {
|
if(!$state_user_transactions || !$state_user_transactions->count()) {
|
||||||
return true;
|
return ['success' => true];
|
||||||
}
|
}
|
||||||
|
|
||||||
// first: decide what todo
|
// first: decide what todo
|
||||||
@ -128,12 +176,20 @@ class StateBalancesTable extends Table
|
|||||||
if($state_user_transactions->count() == 0){
|
if($state_user_transactions->count() == 0){
|
||||||
$clear_state_balance = true;
|
$clear_state_balance = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
$first_state_balance = $state_balances->first();
|
||||||
|
$first_state_balance_decayed = self::calculateDecay(
|
||||||
|
$first_state_balance->amount,
|
||||||
|
$first_state_balance->record_date,
|
||||||
|
$now);
|
||||||
|
|
||||||
$last_state_user_transaction = $state_user_transactions->last();
|
$last_state_user_transaction = $state_user_transactions->last();
|
||||||
$last_transaction = $this->newEntity();
|
$last_state_user_transaction_decayed = self::calculateDecay(
|
||||||
$last_transaction->amount = $last_state_user_transaction->balance;
|
$last_state_user_transaction->balance,
|
||||||
$last_transaction->record_date = $last_state_user_transaction->balance_date;
|
$last_state_user_transaction->balance_date,
|
||||||
|
$now);
|
||||||
// if entrys are nearly the same, we don't need doing anything
|
// if entrys are nearly the same, we don't need doing anything
|
||||||
if(abs($last_transaction->decay - $state_balances->first()->decay) > 100) {
|
if(floor($last_state_user_transaction_decayed/100) !== floor($first_state_balance_decayed/100)) {
|
||||||
$recalculate_state_user_transactions_balance = true;
|
$recalculate_state_user_transactions_balance = true;
|
||||||
$update_state_balance = true;
|
$update_state_balance = true;
|
||||||
}
|
}
|
||||||
@ -194,36 +250,27 @@ class StateBalancesTable extends Table
|
|||||||
if($transaction->transaction_type_id > 2) {
|
if($transaction->transaction_type_id > 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//echo "transaction id: ".$transaction->id . "<br>";
|
|
||||||
$amount_date = null;
|
|
||||||
$amount = 0;
|
$amount = 0;
|
||||||
|
|
||||||
if($transaction->transaction_type_id == 1) { // creation
|
if($transaction->transaction_type_id == 1) { // creation
|
||||||
$temp = $transaction->transaction_creation;
|
$amount = intval($transaction->transaction_creation->amount);
|
||||||
|
|
||||||
/*$balance_temp = $this->newEntity();
|
|
||||||
$balance_temp->amount = $temp->amount;
|
|
||||||
$balance_temp->record_date = $temp->target_date;
|
|
||||||
*/
|
|
||||||
$amount = intval($temp->amount);//$balance_temp->partDecay($transaction->received);
|
|
||||||
$amount_date = $temp->target_date;
|
|
||||||
|
|
||||||
//$amount_date =
|
|
||||||
} else if($transaction->transaction_type_id == 2) { // transfer
|
} else if($transaction->transaction_type_id == 2) { // transfer
|
||||||
|
|
||||||
$temp = $transaction->transaction_send_coin;
|
$temp = $transaction->transaction_send_coin;
|
||||||
$amount = intval($temp->amount);
|
$amount = intval($temp->amount);
|
||||||
// reverse if sender
|
// reverse if sender
|
||||||
if($stateUserId == $temp->state_user_id) {
|
if($stateUserId == $temp->state_user_id) {
|
||||||
$amount *= -1.0;
|
$amount *= -1.0;
|
||||||
}
|
}
|
||||||
$amount_date = $transaction->received;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
$amount_date = $transaction->received;
|
||||||
if($i == 0) {
|
if($i == 0) {
|
||||||
$balance_cursor->amount = $amount;
|
$balance_cursor->amount = $amount;
|
||||||
} else {
|
} else {
|
||||||
$balance_cursor->amount = $balance_cursor->partDecay($amount_date) + $amount;
|
|
||||||
|
//$balance_cursor->amount = $balance_cursor->partDecay($amount_date) + $amount;
|
||||||
|
$balance_cursor->amount =
|
||||||
|
$this->calculateDecay($balance_cursor->amount, $balance_cursor->record_date, $amount_date)
|
||||||
|
+ $amount;
|
||||||
}
|
}
|
||||||
//echo "new balance: " . $balance_cursor->amount . "<br>";
|
//echo "new balance: " . $balance_cursor->amount . "<br>";
|
||||||
|
|
||||||
@ -261,7 +308,7 @@ class StateBalancesTable extends Table
|
|||||||
return ['success' => false, 'error' => 'error saving state balance', 'details' => $state_balance->getErrors()];
|
return ['success' => false, 'error' => 'error saving state balance', 'details' => $state_balance->getErrors()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return ['success' => true];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ use Cake\Validation\Validator;
|
|||||||
* @method \App\Model\Entity\StateUserTransaction[] patchEntities($entities, array $data, array $options = [])
|
* @method \App\Model\Entity\StateUserTransaction[] patchEntities($entities, array $data, array $options = [])
|
||||||
* @method \App\Model\Entity\StateUserTransaction findOrCreate($search, callable $callback = null, $options = [])
|
* @method \App\Model\Entity\StateUserTransaction findOrCreate($search, callable $callback = null, $options = [])
|
||||||
*/
|
*/
|
||||||
class StateUserTransactionsTable extends Table
|
class StateUserTransactionsTable extends AppTable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initialize method
|
* Initialize method
|
||||||
|
|||||||
@ -20,7 +20,7 @@ use Cake\Validation\Validator;
|
|||||||
* @method \App\Model\Entity\TransactionType[] patchEntities($entities, array $data, array $options = [])
|
* @method \App\Model\Entity\TransactionType[] patchEntities($entities, array $data, array $options = [])
|
||||||
* @method \App\Model\Entity\TransactionType findOrCreate($search, callable $callback = null, $options = [])
|
* @method \App\Model\Entity\TransactionType findOrCreate($search, callable $callback = null, $options = [])
|
||||||
*/
|
*/
|
||||||
class TransactionTypesTable extends Table
|
class TransactionTypesTable extends AppTable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initialize method
|
* Initialize method
|
||||||
@ -55,7 +55,7 @@ class TransactionTypesTable extends Table
|
|||||||
|
|
||||||
$validator
|
$validator
|
||||||
->scalar('name')
|
->scalar('name')
|
||||||
->maxLength('name', 24)
|
->maxLength('name', 45)
|
||||||
->requirePresence('name', 'create')
|
->requirePresence('name', 'create')
|
||||||
->notEmptyString('name');
|
->notEmptyString('name');
|
||||||
|
|
||||||
@ -66,4 +66,55 @@ class TransactionTypesTable extends Table
|
|||||||
|
|
||||||
return $validator;
|
return $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fillWithDefault()
|
||||||
|
{
|
||||||
|
|
||||||
|
$entry_contents = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'name' => 'creation',
|
||||||
|
'text' => 'create new gradidos for member and also for group (in development)',
|
||||||
|
], [
|
||||||
|
'id' => 2,
|
||||||
|
'name' => 'transfer',
|
||||||
|
'text' => 'send gradidos from one member to another, also cross group transfer',
|
||||||
|
], [
|
||||||
|
'id' => 3,
|
||||||
|
'name' => 'group create',
|
||||||
|
'text' => 'create a new group, trigger creation of new hedera topic and new blockchain on node server'
|
||||||
|
], [
|
||||||
|
'id' => 4,
|
||||||
|
'name' => 'group add member',
|
||||||
|
'text' => 'add user to a group or move if he was already in a group'
|
||||||
|
], [
|
||||||
|
'id' => 5,
|
||||||
|
'name' => 'group remove member',
|
||||||
|
'text' => 'remove user from group, maybe he was moved elsewhere'
|
||||||
|
],[
|
||||||
|
'id' => 6,
|
||||||
|
'name' => 'hedera topic create',
|
||||||
|
'text' => 'create new topic on hedera'
|
||||||
|
],[
|
||||||
|
'id' => 7,
|
||||||
|
'name' => 'hedera topic send message',
|
||||||
|
'text' => 'send consensus message over hedera topic'
|
||||||
|
],[
|
||||||
|
'id' => 8,
|
||||||
|
'name' => 'hedera account create',
|
||||||
|
'text' => 'create new account on hedera for holding some founds with unencrypted keys'
|
||||||
|
],[
|
||||||
|
'id' => 9,
|
||||||
|
'name' => 'decay start',
|
||||||
|
'text' => 'signalize the starting point for decay calculation, allowed only once per chain'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$entities = $this->newEntities($entry_contents);
|
||||||
|
$this->truncate();
|
||||||
|
$save_results = $this->saveManyWithErrors($entities);
|
||||||
|
if(!$save_results['success']) {
|
||||||
|
$save_results['msg'] = 'error by saving default transaction types';
|
||||||
|
}
|
||||||
|
return $save_results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace App\Model\Table;
|
namespace App\Model\Table;
|
||||||
|
|
||||||
use Cake\ORM\Query;
|
|
||||||
use Cake\ORM\RulesChecker;
|
use Cake\ORM\RulesChecker;
|
||||||
use Cake\ORM\Table;
|
use Cake\ORM\Table;
|
||||||
use Cake\Validation\Validator;
|
use Cake\Validation\Validator;
|
||||||
use Cake\ORM\TableRegistry;
|
use Cake\ORM\TableRegistry;
|
||||||
use Cake\I18n\Number;
|
use Cake\I18n\FrozenTime;
|
||||||
/**
|
/**
|
||||||
* Transactions Model
|
* Transactions Model
|
||||||
*
|
*
|
||||||
@ -172,18 +172,19 @@ class TransactionsTable extends Table
|
|||||||
//var_dump($su_transaction);
|
//var_dump($su_transaction);
|
||||||
//die("step");
|
//die("step");
|
||||||
// add decay transactions
|
// add decay transactions
|
||||||
if($i > 0 && $decay == true)
|
$prev = null;
|
||||||
{
|
if($i > 0 ) {
|
||||||
$prev = $stateUserTransactions[$i-1];
|
$prev = $stateUserTransactions[$i-1];
|
||||||
|
}
|
||||||
|
if($prev && $decay == true)
|
||||||
|
{
|
||||||
|
|
||||||
if($prev->balance > 0) {
|
if($prev->balance > 0) {
|
||||||
// var_dump($stateUserTransactions);
|
// var_dump($stateUserTransactions);
|
||||||
$current = $su_transaction;
|
$current = $su_transaction;
|
||||||
//echo "decay between " . $prev->transaction_id . " and " . $current->transaction_id . "<br>";
|
//echo "decay between " . $prev->transaction_id . " and " . $current->transaction_id . "<br>";
|
||||||
$interval = $current->balance_date->diff($prev->balance_date);
|
$calculated_decay = $stateBalancesTable->calculateDecay($prev->balance, $prev->balance_date, $current->balance_date, true);
|
||||||
$state_balance->amount = $prev->balance;
|
$balance = floatval($prev->balance - $calculated_decay['balance']);
|
||||||
$state_balance->record_date = $prev->balance_date;
|
|
||||||
$diff_amount = $state_balance->partDecay($current->balance_date);
|
|
||||||
$balance = floatval($prev->balance - $diff_amount);
|
|
||||||
// skip small decays (smaller than 0,00 GDD)
|
// skip small decays (smaller than 0,00 GDD)
|
||||||
|
|
||||||
if(abs($balance) >= 100) {
|
if(abs($balance) >= 100) {
|
||||||
@ -192,7 +193,7 @@ class TransactionsTable extends Table
|
|||||||
$final_transactions[] = [
|
$final_transactions[] = [
|
||||||
'type' => 'decay',
|
'type' => 'decay',
|
||||||
'balance' => $balance,
|
'balance' => $balance,
|
||||||
'decay_duration' => $interval->format('%a days, %H hours, %I minutes, %S seconds'),
|
'decay_duration' => $calculated_decay['interval']->format('%a days, %H hours, %I minutes, %S seconds'),
|
||||||
'memo' => ''
|
'memo' => ''
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -211,12 +212,16 @@ class TransactionsTable extends Table
|
|||||||
echo "<br>";*/
|
echo "<br>";*/
|
||||||
if($su_transaction->transaction_type_id == 1) { // creation
|
if($su_transaction->transaction_type_id == 1) { // creation
|
||||||
$creation = $transaction->transaction_creation;
|
$creation = $transaction->transaction_creation;
|
||||||
|
$balance = $stateBalancesTable->calculateDecay($creation->amount, $creation->target_date, $transaction->received);
|
||||||
|
|
||||||
$final_transactions[] = [
|
$final_transactions[] = [
|
||||||
'name' => 'Gradido Akademie',
|
'name' => 'Gradido Akademie',
|
||||||
'type' => 'creation',
|
'type' => 'creation',
|
||||||
'transaction_id' => $transaction->id,
|
'transaction_id' => $transaction->id,
|
||||||
'date' => $creation->target_date,
|
'date' => $transaction->received,// $creation->target_date,
|
||||||
'balance' => $creation->amount,
|
'target_date' => $creation->target_date,
|
||||||
|
'creation_amount' => $creation->amount,
|
||||||
|
'balance' => $balance,
|
||||||
'memo' => $transaction->memo
|
'memo' => $transaction->memo
|
||||||
];
|
];
|
||||||
} else if($su_transaction->transaction_type_id == 2) { // transfer or send coins
|
} else if($su_transaction->transaction_type_id == 2) { // transfer or send coins
|
||||||
@ -256,14 +261,21 @@ class TransactionsTable extends Table
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($i == $stateUserTransactionsCount-1 && $decay == true) {
|
if($i == $stateUserTransactionsCount-1 && $decay == true) {
|
||||||
$state_balance->amount = $su_transaction->balance;
|
$calculated_decay = $stateBalancesTable->calculateDecay(
|
||||||
$state_balance->record_date = $su_transaction->balance_date;
|
$su_transaction->balance,
|
||||||
$balance = floatval($su_transaction->balance - $state_balance->decay);
|
$su_transaction->balance_date, new FrozenTime(), true);
|
||||||
|
$decay_start_date = $stateBalancesTable->getDecayStartDateCached();
|
||||||
|
$duration = $su_transaction->balance_date->timeAgoInWords();
|
||||||
|
if($decay_start_date > $su_transaction->balance_date) {
|
||||||
|
$duration = $decay_start_date->timeAgoInWords();
|
||||||
|
}
|
||||||
|
$balance = floatval($su_transaction->balance - $calculated_decay['balance']);
|
||||||
if($balance > 100) {
|
if($balance > 100) {
|
||||||
$final_transactions[] = [
|
$final_transactions[] = [
|
||||||
'type' => 'decay',
|
'type' => 'decay',
|
||||||
'balance' => $balance,
|
'balance' => $balance,
|
||||||
'decay_duration' => $su_transaction->balance_date->timeAgoInWords(),
|
'decay_duration' => $duration,
|
||||||
|
'last_decay' => true,
|
||||||
'memo' => ''
|
'memo' => ''
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -273,4 +285,169 @@ class TransactionsTable extends Table
|
|||||||
return $final_transactions;
|
return $final_transactions;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateTxHash($transaction, $signatureMapString)
|
||||||
|
{
|
||||||
|
$transaction_id = $transaction->id;
|
||||||
|
$previousTxHash = null;
|
||||||
|
if($transaction_id > 1) {
|
||||||
|
try {
|
||||||
|
$previousTransaction = $this
|
||||||
|
->find('all', ['contain' => false])
|
||||||
|
->select(['tx_hash'])
|
||||||
|
->where(['id' => $transaction_id - 1])
|
||||||
|
->first();
|
||||||
|
/*$previousTransaction = $transactionsTable->get($this->mTransactionID - 1, [
|
||||||
|
'contain' => false,
|
||||||
|
'fields' => ['tx_hash']
|
||||||
|
]);*/
|
||||||
|
} catch(Cake\Datasource\Exception\RecordNotFoundException $ex) {
|
||||||
|
return ['state' => 'error', 'msg' => 'previous transaction not found', 'details' => $ex->getMessage()];
|
||||||
|
}
|
||||||
|
if(!$previousTransaction) {
|
||||||
|
// shouldn't occur
|
||||||
|
return ['state' => 'error', 'msg' => 'previous transaction not found'];
|
||||||
|
}
|
||||||
|
$previousTxHash = $previousTransaction->tx_hash;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//$transactionEntity->received = $transactionsTable->get($transactionEntity->id, ['contain' => false, 'fields' => ['received']])->received;
|
||||||
|
$transaction->received = $this
|
||||||
|
->find('all', ['contain' => false])
|
||||||
|
->where(['id' => $transaction->id])
|
||||||
|
->select(['received'])->first()->received;
|
||||||
|
} catch(Cake\Datasource\Exception\RecordNotFoundException $ex) {
|
||||||
|
return ['state' => 'error', 'msg' => 'current transaction not found in db', 'details' => $ex->getMessage()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate tx hash
|
||||||
|
// previous tx hash + id + received + sigMap as string
|
||||||
|
// Sodium use for the generichash function BLAKE2b today (11.11.2019), mabye change in the future
|
||||||
|
$state = \Sodium\crypto_generichash_init();
|
||||||
|
//echo "prev hash: $previousTxHash\n";
|
||||||
|
if($previousTxHash != null) {
|
||||||
|
\Sodium\crypto_generichash_update($state, stream_get_contents($previousTxHash));
|
||||||
|
}
|
||||||
|
//echo "id: " . $transactionEntity->id . "\n";
|
||||||
|
\Sodium\crypto_generichash_update($state, strval($transaction->id));
|
||||||
|
//echo "received: " . $transactionEntity->received;
|
||||||
|
\Sodium\crypto_generichash_update($state, $transaction->received->i18nFormat('yyyy-MM-dd HH:mm:ss'));
|
||||||
|
\Sodium\crypto_generichash_update($state, $signatureMapString);
|
||||||
|
$transaction->tx_hash = \Sodium\crypto_generichash_final($state);
|
||||||
|
if ($this->save($transaction)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ['state' => 'error', 'msg' => 'error by saving transaction', 'details' => $transaction->getErrors()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @return: false if no decay start block found
|
||||||
|
* @return: DateTime Object with start date if one start block found
|
||||||
|
* @return: ['state':'error'] if more than one found
|
||||||
|
*/
|
||||||
|
public function getDecayStartDate()
|
||||||
|
{
|
||||||
|
$transaction = $this->find()->where(['transaction_type_id' => 9])->select(['received'])->order(['received' => 'ASC']);
|
||||||
|
if($transaction->count() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $transaction->first()->received;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fillStateUserTransactions()
|
||||||
|
{
|
||||||
|
$missing_transaction_ids = [];
|
||||||
|
$transaction_ids = $this
|
||||||
|
->find('all')
|
||||||
|
->select(['id', 'transaction_type_id'])
|
||||||
|
->order(['id'])
|
||||||
|
->where(['transaction_type_id <' => 6])
|
||||||
|
->all()
|
||||||
|
;
|
||||||
|
$state_user_transaction_ids = $this->StateUserTransactions
|
||||||
|
->find('all')
|
||||||
|
->select(['transaction_id'])
|
||||||
|
->group(['transaction_id'])
|
||||||
|
->order(['transaction_id'])
|
||||||
|
->toArray()
|
||||||
|
;
|
||||||
|
$i2 = 0;
|
||||||
|
$count = count($state_user_transaction_ids);
|
||||||
|
foreach($transaction_ids as $tr_id) {
|
||||||
|
//echo "$i1: ";
|
||||||
|
if($i2 >= $count) {
|
||||||
|
$missing_transaction_ids[] = $tr_id;
|
||||||
|
//echo "adding to missing: $tr_id, continue <br>";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$stu_id = $state_user_transaction_ids[$i2];
|
||||||
|
if($tr_id->id == $stu_id->transaction_id) {
|
||||||
|
$i2++;
|
||||||
|
//echo "after i2++: $i2<br>";
|
||||||
|
} else if($tr_id->id < $stu_id->transaction_id) {
|
||||||
|
$missing_transaction_ids[] = $tr_id;
|
||||||
|
//echo "adding to missing: $tr_id<br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$tablesForType = [
|
||||||
|
1 => $this->TransactionCreations,
|
||||||
|
2 => $this->TransactionSendCoins,
|
||||||
|
3 => $this->TransactionGroupCreates,
|
||||||
|
4 => $this->TransactionGroupAddaddress,
|
||||||
|
5 => $this->TransactionGroupAddaddress
|
||||||
|
];
|
||||||
|
$idsForType = [];
|
||||||
|
foreach($missing_transaction_ids as $i => $transaction) {
|
||||||
|
if(!isset($idsForType[$transaction->transaction_type_id])) {
|
||||||
|
$idsForType[$transaction->transaction_type_id] = [];
|
||||||
|
}
|
||||||
|
$idsForType[$transaction->transaction_type_id][] = $transaction->id;
|
||||||
|
}
|
||||||
|
$entities = [];
|
||||||
|
$state_user_ids = [];
|
||||||
|
foreach($idsForType as $type_id => $transaction_ids) {
|
||||||
|
$specific_transactions = $tablesForType[$type_id]->find('all')->where(['transaction_id IN' => $transaction_ids])->toArray();
|
||||||
|
$keys = $tablesForType[$type_id]->getSchema()->columns();
|
||||||
|
//var_dump($keys);
|
||||||
|
foreach($specific_transactions as $specific) {
|
||||||
|
|
||||||
|
foreach($keys as $key) {
|
||||||
|
if(preg_match('/_user_id/', $key)) {
|
||||||
|
$entity = $this->StateUserTransactions->newEntity();
|
||||||
|
$entity->transaction_id = $specific['transaction_id'];
|
||||||
|
$entity->transaction_type_id = $type_id;
|
||||||
|
$entity->state_user_id = $specific[$key];
|
||||||
|
if(!in_array($entity->state_user_id, $state_user_ids)) {
|
||||||
|
array_push($state_user_ids, $entity->state_user_id);
|
||||||
|
}
|
||||||
|
$entities[] = $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(count($state_user_ids) < 1) {
|
||||||
|
return ['success' => true];
|
||||||
|
}
|
||||||
|
//var_dump($entities);
|
||||||
|
$stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers');
|
||||||
|
$existingStateUsers = $stateUsersTable->find('all')->select(['id'])->where(['id IN' => $state_user_ids])->order(['id'])->all();
|
||||||
|
$existing_state_user_ids = [];
|
||||||
|
$finalEntities = [];
|
||||||
|
foreach($existingStateUsers as $stateUser) {
|
||||||
|
$existing_state_user_ids[] = $stateUser->id;
|
||||||
|
}
|
||||||
|
foreach($entities as $entity) {
|
||||||
|
if(in_array($entity->state_user_id, $existing_state_user_ids)) {
|
||||||
|
array_push($finalEntities, $entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$save_results = $this->StateUserTransactions->saveManyWithErrors($finalEntities);
|
||||||
|
if(!$save_results['success']) {
|
||||||
|
$save_results['msg'] = 'error by saving at least one state user transaction';
|
||||||
|
}
|
||||||
|
return $save_results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,6 +98,11 @@ class Transaction extends TransactionBase {
|
|||||||
return $sigPairs[0]->getPubKey();
|
return $sigPairs[0]->getPubKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFirstSigningUser()
|
||||||
|
{
|
||||||
|
return $this->getStateUserFromPublickey($this->getFirstPublic());
|
||||||
|
}
|
||||||
|
|
||||||
public function getId() {
|
public function getId() {
|
||||||
return $this->mProtoTransaction->getId();
|
return $this->mProtoTransaction->getId();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,16 @@ class TransactionBase {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getStateUserFromPublickey($publicKey) {
|
||||||
|
$stateUsersTable = self::getTable('state_users');
|
||||||
|
$stateUser = $stateUsersTable->find('all')->where(['public_key' => $publicKey])->first();
|
||||||
|
if($stateUser) {
|
||||||
|
return $stateUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function updateStateBalance($stateUserId, $addAmountCent, $recordDate) {
|
protected function updateStateBalance($stateUserId, $addAmountCent, $recordDate) {
|
||||||
$stateBalancesTable = self::getTable('stateBalances');
|
$stateBalancesTable = self::getTable('stateBalances');
|
||||||
@ -72,9 +82,11 @@ class TransactionBase {
|
|||||||
//debug($stateBalanceQuery);
|
//debug($stateBalanceQuery);
|
||||||
|
|
||||||
if($stateBalanceQuery->count() > 0) {
|
if($stateBalanceQuery->count() > 0) {
|
||||||
|
|
||||||
$stateBalanceEntry = $stateBalanceQuery->first();
|
$stateBalanceEntry = $stateBalanceQuery->first();
|
||||||
$stateBalanceEntry->amount = $stateBalanceEntry->partDecay($recordDate) + $addAmountCent;
|
$stateBalanceEntry->amount =
|
||||||
$stateBalanceEntry->amount += $addAmountCent;
|
$stateBalancesTable->calculateDecay($stateBalanceEntry->amount, $stateBalanceEntry->record_date, $recordDate)
|
||||||
|
+ $addAmountCent;
|
||||||
} else {
|
} else {
|
||||||
$stateBalanceEntry = $stateBalancesTable->newEntity();
|
$stateBalanceEntry = $stateBalancesTable->newEntity();
|
||||||
$stateBalanceEntry->state_user_id = $stateUserId;
|
$stateBalanceEntry->state_user_id = $stateUserId;
|
||||||
@ -93,11 +105,12 @@ class TransactionBase {
|
|||||||
|
|
||||||
protected function addStateUserTransaction($stateUserId, $transactionId, $transactionTypeId, $balance, $balance_date) {
|
protected function addStateUserTransaction($stateUserId, $transactionId, $transactionTypeId, $balance, $balance_date) {
|
||||||
$stateUserTransactionTable = self::getTable('state_user_transactions');
|
$stateUserTransactionTable = self::getTable('state_user_transactions');
|
||||||
|
|
||||||
$stateUserTransactions = $stateUserTransactionTable
|
$stateUserTransactions = $stateUserTransactionTable
|
||||||
->find('all')
|
->find('all')
|
||||||
->where(['state_user_id' => $stateUserId])
|
->where(['state_user_id' => $stateUserId])
|
||||||
->order(['transaction_id DESC']);
|
->order(['transaction_id DESC']);
|
||||||
|
$new_balance = $balance;
|
||||||
if($stateUserTransactions->count() > 0) {
|
if($stateUserTransactions->count() > 0) {
|
||||||
$stateBalanceTable = self::getTable('state_balances');
|
$stateBalanceTable = self::getTable('state_balances');
|
||||||
$state_user_transaction = $stateUserTransactions->first();
|
$state_user_transaction = $stateUserTransactions->first();
|
||||||
@ -105,16 +118,17 @@ class TransactionBase {
|
|||||||
$this->addError('TransactionBase::addStateUserTransaction', 'state_user_transaction is zero, no first entry exist?');
|
$this->addError('TransactionBase::addStateUserTransaction', 'state_user_transaction is zero, no first entry exist?');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$balance_entity = $stateBalanceTable->newEntity();
|
$new_balance += $stateBalanceTable->calculateDecay(
|
||||||
$balance_entity->amount = $state_user_transaction->balance;
|
$state_user_transaction->balance,
|
||||||
$balance_entity->record_date = $state_user_transaction->balance_date;
|
$state_user_transaction->balance_date,
|
||||||
$balance = $balance_entity->decay + $balance;
|
$balance_date
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$entity = $stateUserTransactionTable->newEntity();
|
$entity = $stateUserTransactionTable->newEntity();
|
||||||
$entity->state_user_id = $stateUserId;
|
$entity->state_user_id = $stateUserId;
|
||||||
$entity->transaction_id = $transactionId;
|
$entity->transaction_id = $transactionId;
|
||||||
$entity->transaction_type_id = $transactionTypeId;
|
$entity->transaction_type_id = $transactionTypeId;
|
||||||
$entity->balance = $balance;
|
$entity->balance = $new_balance;
|
||||||
$entity->balance_date = $balance_date;
|
$entity->balance_date = $balance_date;
|
||||||
|
|
||||||
if(!$stateUserTransactionTable->save($entity)) {
|
if(!$stateUserTransactionTable->save($entity)) {
|
||||||
|
|||||||
@ -72,7 +72,12 @@ class TransactionCreation extends TransactionBase {
|
|||||||
return $this->protoTransactionCreation->getReceiver()->getPubkey();
|
return $this->protoTransactionCreation->getReceiver()->getPubkey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getReceiverUser() {
|
||||||
|
return $this->getStateUserFromPublickey($this->getReceiverPublic());
|
||||||
|
}
|
||||||
|
public function getTargetDate() {
|
||||||
|
return new FrozenDate($this->protoTransactionCreation->getTargetDate()->getSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
public function validate($sigPairs) {
|
public function validate($sigPairs) {
|
||||||
// check if receiver public is not in signature list
|
// check if receiver public is not in signature list
|
||||||
@ -138,8 +143,9 @@ class TransactionCreation extends TransactionBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save($transaction_id, $firstPublic)
|
public function save($transaction_id, $firstPublic, $received)
|
||||||
{
|
{
|
||||||
|
$stateBalancesTable = self::getTable('stateBalances');
|
||||||
|
|
||||||
$transactionCreationEntity = $this->transactionCreationsTable->newEntity();
|
$transactionCreationEntity = $this->transactionCreationsTable->newEntity();
|
||||||
$transactionCreationEntity->transaction_id = $transaction_id;
|
$transactionCreationEntity->transaction_id = $transaction_id;
|
||||||
@ -151,23 +157,27 @@ class TransactionCreation extends TransactionBase {
|
|||||||
$this->addError('TransactionCreation::save', 'couldn\'t get state user id');
|
$this->addError('TransactionCreation::save', 'couldn\'t get state user id');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactionCreationEntity->state_user_id = $receiverUserId;
|
$transactionCreationEntity->state_user_id = $receiverUserId;
|
||||||
$transactionCreationEntity->amount = $this->getAmount();
|
$transactionCreationEntity->amount = $this->getAmount();
|
||||||
$transactionCreationEntity->target_date = $this->protoTransactionCreation->getTargetDate()->getSeconds();
|
$transactionCreationEntity->target_date = $this->protoTransactionCreation->getTargetDate()->getSeconds();
|
||||||
$target_date = new FrozenTime($transactionCreationEntity->target_date);
|
$target_date = new FrozenTime($transactionCreationEntity->target_date);
|
||||||
|
|
||||||
|
$decayed_balance = $stateBalancesTable->calculateDecay($this->getAmount(), $target_date, $received);
|
||||||
|
|
||||||
if(!$this->transactionCreationsTable->save($transactionCreationEntity)) {
|
if(!$this->transactionCreationsTable->save($transactionCreationEntity)) {
|
||||||
$this->addError('TransactionCreation::save', 'error saving transactionCreation with errors: ' . json_encode($transactionCreationEntity->getErrors()));
|
$this->addError('TransactionCreation::save', 'error saving transactionCreation with errors: ' . json_encode($transactionCreationEntity->getErrors()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update state balance
|
// update state balance
|
||||||
$final_balance = $this->updateStateBalance($receiverUserId, $this->getAmount(), $target_date);
|
$final_balance = $this->updateStateBalance($receiverUserId, $decayed_balance, $received);
|
||||||
if(false === $final_balance) {
|
if(false === $final_balance) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decay is a virtual field which is calculated from amount and now() - record_date
|
// decay is a virtual field which is calculated from amount and now() - record_date
|
||||||
if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 1, $this->getAmount(), $target_date)) {
|
if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 1, $decayed_balance, $received)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -186,11 +186,9 @@ class TransactionTransfer extends TransactionBase {
|
|||||||
$local_transfer = $this->protoTransactionTransfer->getLocal();
|
$local_transfer = $this->protoTransactionTransfer->getLocal();
|
||||||
$sender = $local_transfer->getSender();
|
$sender = $local_transfer->getSender();
|
||||||
$senderAmount = $sender->getAmount();
|
$senderAmount = $sender->getAmount();
|
||||||
$senderUserId = $this->getStateUserId($sender->getPubkey());
|
$senderUser = $this->getStateUserFromPublickey($sender->getPubkey());
|
||||||
$receiverUserId = $this->getStateUserId($local_transfer->getReceiver());
|
$receiverUser = $this->getStateUserFromPublickey($local_transfer->getReceiver());
|
||||||
|
|
||||||
$receiverUser = $this->getStateUser($receiverUserId);
|
|
||||||
$senderUser = $this->getStateUser($senderUserId);
|
|
||||||
$serverAdminEmail = Configure::read('ServerAdminEmail');
|
$serverAdminEmail = Configure::read('ServerAdminEmail');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -218,6 +216,25 @@ class TransactionTransfer extends TransactionBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSenderUser()
|
||||||
|
{
|
||||||
|
$local_transfer = $this->protoTransactionTransfer->getLocal();
|
||||||
|
return $this->getStateUserFromPublickey($local_transfer->getSender()->getPubkey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getReceiverUser()
|
||||||
|
{
|
||||||
|
$local_transfer = $this->protoTransactionTransfer->getLocal();
|
||||||
|
return $this->getStateUserFromPublickey($local_transfer->getReceiver());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAmount()
|
||||||
|
{
|
||||||
|
$local_transfer = $this->protoTransactionTransfer->getLocal();
|
||||||
|
$sender = $local_transfer->getSender();
|
||||||
|
return $sender->getAmount();
|
||||||
|
}
|
||||||
|
|
||||||
static public function fromEntity($transactionTransferEntity)
|
static public function fromEntity($transactionTransferEntity)
|
||||||
{
|
{
|
||||||
$protoTransfer = new \Proto\Gradido\GradidoTransfer();
|
$protoTransfer = new \Proto\Gradido\GradidoTransfer();
|
||||||
|
|||||||
@ -11,7 +11,14 @@ $body['decay'] = $this->element('centToFloat', ['cent' => $body['decay'], 'preci
|
|||||||
$body['gdtSum'] = $this->element('centToFloat', ['cent' => $body['gdtSum'], 'precision' => 2]);
|
$body['gdtSum'] = $this->element('centToFloat', ['cent' => $body['gdtSum'], 'precision' => 2]);
|
||||||
|
|
||||||
foreach($body['transactions'] as $i => $transaction) {
|
foreach($body['transactions'] as $i => $transaction) {
|
||||||
$body['transactions'][$i]['balance'] = $this->element('centToFloat', ['cent' => $transaction['balance'], 'precision' => 4]);
|
$useCeil = false;
|
||||||
|
if(isset($transaction['last_decay']) && $transaction['last_decay']) {
|
||||||
|
$useCeil = true;
|
||||||
|
}
|
||||||
|
$body['transactions'][$i]['balance'] = $this->element('centToFloat', ['cent' => $transaction['balance'], 'precision' => 4, 'useCeil' => $useCeil]);
|
||||||
|
if(isset($transaction['creation_amount'])) {
|
||||||
|
$body['transactions'][$i]['creation_amount'] = $this->element('centToFloat', ['cent' => $transaction['creation_amount'], 'precision' => 4]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?><?= json_encode($body) ?>
|
?><?= json_encode($body) ?>
|
||||||
@ -9,7 +9,11 @@
|
|||||||
$cut_places = $precision - 2;
|
$cut_places = $precision - 2;
|
||||||
$transformAmount = $cent;
|
$transformAmount = $cent;
|
||||||
if($cut_places > 0) {
|
if($cut_places > 0) {
|
||||||
$transformAmount = floor($cent / pow(10, $cut_places));
|
if(isset($useCeil) && $useCeil) {
|
||||||
|
$transformAmount = ceil($cent / pow(10, $cut_places));
|
||||||
|
} else {
|
||||||
|
$transformAmount = floor($cent / pow(10, $cut_places));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if($cut_places < 0) {
|
if($cut_places < 0) {
|
||||||
$cut_places = 0;
|
$cut_places = 0;
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
<?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->assign('title', __('Gradido Transaktion fehlgeschlagen'));
|
||||||
|
|
||||||
|
$transaction_body = $transaction->getTransactionBody();
|
||||||
|
$specific_transaction = $transaction_body->getSpecificTransaction();
|
||||||
|
$transaction_type_name = $transaction_body->getTransactionTypeName();
|
||||||
|
|
||||||
|
?><?= __('Hallo') ?> <?= $user->first_name ?> <?= $user->last_name ?>,
|
||||||
|
|
||||||
|
<?= __('Deine letzte Transaktion ist leider fehlgeschlagen.') ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if($reason != 'parse') :
|
||||||
|
if($transaction_type_name === 'creation') : ?><?= __('Du wolltest {0} für {1} schöpfen.',
|
||||||
|
$this->element('printGradido', ['number' => $specific_transaction->getAmount(), 'raw' => true]),
|
||||||
|
$specific_transaction->getReceiverUser()->getEmailWithName()) ?>
|
||||||
|
|
||||||
|
<?= __('Das Zieldatum war: ') . $specific_transaction->getTargetDate()->format('d.m.Y') ?>
|
||||||
|
<?php elseif($transaction_type_name === 'transfer'): ?>
|
||||||
|
<?= __('Du wolltest {0} an {1} senden.',
|
||||||
|
$this->element('printGradido', ['number' => $specific_transaction->getAmount(), 'raw' => true]),
|
||||||
|
$specific_transaction->getReceiverUser()->getEmailWithName()) ?>
|
||||||
|
<?php endif; endif; ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?= __('Das ist schief gelaufen: ') ?>
|
||||||
|
|
||||||
|
<?php switch($reason) {
|
||||||
|
case 'save': echo __('Fehler beim speichern in der Datenbank. Bitte versuche es später erneut'); break;
|
||||||
|
case 'parse': echo __('Fehler beim parsen der Transaktion. Bitte versuche es später erneut'); break;
|
||||||
|
case 'validate':
|
||||||
|
$errors = $transaction->getErrors();
|
||||||
|
foreach($errors as $error) {
|
||||||
|
//echo "\t".json_encode($error);
|
||||||
|
echo "\n\t".$error[array_keys($error)[0]]."\n";
|
||||||
|
}
|
||||||
|
}?>
|
||||||
|
|
||||||
|
|
||||||
|
<?= __('Bitte antworte nicht auf diese E-Mail!'); ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?= __('Mit freundlichen Grüßen'); ?>
|
||||||
|
Gradido Community Server
|
||||||
23
community_server/src/Template/Migrations/add.ctp
Normal file
23
community_server/src/Template/Migrations/add.ctp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @var \App\View\AppView $this
|
||||||
|
* @var \App\Model\Entity\Migration $migration
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||||
|
<ul class="side-nav">
|
||||||
|
<li class="heading"><?= __('Actions') ?></li>
|
||||||
|
<li><?= $this->Html->link(__('List Migrations'), ['action' => 'index']) ?></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="migrations form large-9 medium-8 columns content">
|
||||||
|
<?= $this->Form->create($migration) ?>
|
||||||
|
<fieldset>
|
||||||
|
<legend><?= __('Add Migration') ?></legend>
|
||||||
|
<?php
|
||||||
|
echo $this->Form->control('db_version');
|
||||||
|
?>
|
||||||
|
</fieldset>
|
||||||
|
<?= $this->Form->button(__('Submit')) ?>
|
||||||
|
<?= $this->Form->end() ?>
|
||||||
|
</div>
|
||||||
29
community_server/src/Template/Migrations/edit.ctp
Normal file
29
community_server/src/Template/Migrations/edit.ctp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @var \App\View\AppView $this
|
||||||
|
* @var \App\Model\Entity\Migration $migration
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||||
|
<ul class="side-nav">
|
||||||
|
<li class="heading"><?= __('Actions') ?></li>
|
||||||
|
<li><?= $this->Form->postLink(
|
||||||
|
__('Delete'),
|
||||||
|
['action' => 'delete', $migration->id],
|
||||||
|
['confirm' => __('Are you sure you want to delete # {0}?', $migration->id)]
|
||||||
|
)
|
||||||
|
?></li>
|
||||||
|
<li><?= $this->Html->link(__('List Migrations'), ['action' => 'index']) ?></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="migrations form large-9 medium-8 columns content">
|
||||||
|
<?= $this->Form->create($migration) ?>
|
||||||
|
<fieldset>
|
||||||
|
<legend><?= __('Edit Migration') ?></legend>
|
||||||
|
<?php
|
||||||
|
echo $this->Form->control('db_version');
|
||||||
|
?>
|
||||||
|
</fieldset>
|
||||||
|
<?= $this->Form->button(__('Submit')) ?>
|
||||||
|
<?= $this->Form->end() ?>
|
||||||
|
</div>
|
||||||
47
community_server/src/Template/Migrations/index.ctp
Normal file
47
community_server/src/Template/Migrations/index.ctp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @var \App\View\AppView $this
|
||||||
|
* @var \App\Model\Entity\Migration[]|\Cake\Collection\CollectionInterface $migrations
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||||
|
<ul class="side-nav">
|
||||||
|
<li class="heading"><?= __('Actions') ?></li>
|
||||||
|
<li><?= $this->Html->link(__('New Migration'), ['action' => 'add']) ?></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="migrations index large-9 medium-8 columns content">
|
||||||
|
<h3><?= __('Migrations') ?></h3>
|
||||||
|
<table cellpadding="0" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"><?= $this->Paginator->sort('id') ?></th>
|
||||||
|
<th scope="col"><?= $this->Paginator->sort('db_version') ?></th>
|
||||||
|
<th scope="col" class="actions"><?= __('Actions') ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($migrations as $migration): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= $this->Number->format($migration->id) ?></td>
|
||||||
|
<td><?= $this->Number->format($migration->db_version) ?></td>
|
||||||
|
<td class="actions">
|
||||||
|
<?= $this->Html->link(__('View'), ['action' => 'view', $migration->id]) ?>
|
||||||
|
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $migration->id]) ?>
|
||||||
|
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $migration->id], ['confirm' => __('Are you sure you want to delete # {0}?', $migration->id)]) ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="paginator">
|
||||||
|
<ul class="pagination">
|
||||||
|
<?= $this->Paginator->first('<< ' . __('first')) ?>
|
||||||
|
<?= $this->Paginator->prev('< ' . __('previous')) ?>
|
||||||
|
<?= $this->Paginator->numbers() ?>
|
||||||
|
<?= $this->Paginator->next(__('next') . ' >') ?>
|
||||||
|
<?= $this->Paginator->last(__('last') . ' >>') ?>
|
||||||
|
</ul>
|
||||||
|
<p><?= $this->Paginator->counter(['format' => __('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')]) ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
18
community_server/src/Template/Migrations/migrate.ctp
Normal file
18
community_server/src/Template/Migrations/migrate.ctp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
?><h2>Migrate DB</h2>
|
||||||
|
<p>Migrate from Version <?= $db_version ?></p>
|
||||||
|
<?php if($result['success']) : ?>
|
||||||
|
<h3><success>Success</success></h3>
|
||||||
|
<?php else : ?>
|
||||||
|
<h3><error>Error</error></h3>
|
||||||
|
<p><?= json_encode($result) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<p><?= $this->Html->link('Back to Dashboard', ['controller' => 'Dashboard', 'action' => 'index']) ?></p>
|
||||||
|
|
||||||
28
community_server/src/Template/Migrations/view.ctp
Normal file
28
community_server/src/Template/Migrations/view.ctp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @var \App\View\AppView $this
|
||||||
|
* @var \App\Model\Entity\Migration $migration
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||||
|
<ul class="side-nav">
|
||||||
|
<li class="heading"><?= __('Actions') ?></li>
|
||||||
|
<li><?= $this->Html->link(__('Edit Migration'), ['action' => 'edit', $migration->id]) ?> </li>
|
||||||
|
<li><?= $this->Form->postLink(__('Delete Migration'), ['action' => 'delete', $migration->id], ['confirm' => __('Are you sure you want to delete # {0}?', $migration->id)]) ?> </li>
|
||||||
|
<li><?= $this->Html->link(__('List Migrations'), ['action' => 'index']) ?> </li>
|
||||||
|
<li><?= $this->Html->link(__('New Migration'), ['action' => 'add']) ?> </li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="migrations view large-9 medium-8 columns content">
|
||||||
|
<h3><?= h($migration->id) ?></h3>
|
||||||
|
<table class="vertical-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><?= __('Id') ?></th>
|
||||||
|
<td><?= $this->Number->format($migration->id) ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><?= __('Db Version') ?></th>
|
||||||
|
<td><?= $this->Number->format($migration->db_version) ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@ -35,7 +35,8 @@
|
|||||||
<?php
|
<?php
|
||||||
echo $this->Form->control('state_group_id', ['options' => $stateGroups]);
|
echo $this->Form->control('state_group_id', ['options' => $stateGroups]);
|
||||||
echo $this->Form->control('transaction_type_id', ['options' => $transactionTypes]);
|
echo $this->Form->control('transaction_type_id', ['options' => $transactionTypes]);
|
||||||
echo $this->Form->control('received');
|
echo $this->Form->control('memo', ['type' => 'textarea']);
|
||||||
|
echo $this->Form->control('blockchain_type_id', ['options' => $blockchainTypes]);
|
||||||
?>
|
?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<?= $this->Form->button(__('Submit')) ?>
|
<?= $this->Form->button(__('Submit')) ?>
|
||||||
|
|||||||
44
community_server/tests/Fixture/MigrationsFixture.php
Normal file
44
community_server/tests/Fixture/MigrationsFixture.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Test\Fixture;
|
||||||
|
|
||||||
|
use Cake\TestSuite\Fixture\TestFixture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MigrationsFixture
|
||||||
|
*/
|
||||||
|
class MigrationsFixture 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->records = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'db_version' => 1,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Test\TestCase\Controller;
|
||||||
|
|
||||||
|
use App\Controller\MigrationsController;
|
||||||
|
use Cake\TestSuite\IntegrationTestTrait;
|
||||||
|
use Cake\TestSuite\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App\Controller\MigrationsController Test Case
|
||||||
|
*
|
||||||
|
* @uses \App\Controller\MigrationsController
|
||||||
|
*/
|
||||||
|
class MigrationsControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
use IntegrationTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixtures
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $fixtures = [
|
||||||
|
'app.Migrations',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test index method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testIndex()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test view method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testView()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test add method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testAdd()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test edit method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testEdit()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test delete method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testDelete()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Test\TestCase\Model\Table;
|
||||||
|
|
||||||
|
use App\Model\Table\MigrationsTable;
|
||||||
|
use Cake\ORM\TableRegistry;
|
||||||
|
use Cake\TestSuite\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App\Model\Table\MigrationsTable Test Case
|
||||||
|
*/
|
||||||
|
class MigrationsTableTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test subject
|
||||||
|
*
|
||||||
|
* @var \App\Model\Table\MigrationsTable
|
||||||
|
*/
|
||||||
|
public $Migrations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixtures
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $fixtures = [
|
||||||
|
'app.Migrations',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setUp method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$config = TableRegistry::getTableLocator()->exists('Migrations') ? [] : ['className' => MigrationsTable::class];
|
||||||
|
$this->Migrations = TableRegistry::getTableLocator()->get('Migrations', $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tearDown method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
unset($this->Migrations);
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test initialize method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testInitialize()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test validationDefault method
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testValidationDefault()
|
||||||
|
{
|
||||||
|
$this->markTestIncomplete('Not implemented yet.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,8 +26,8 @@ services:
|
|||||||
#########################################################
|
#########################################################
|
||||||
login-server:
|
login-server:
|
||||||
build:
|
build:
|
||||||
target: login_server_debug
|
target: login_server_alpine_debug
|
||||||
dockerfile: Dockerfile.debug
|
dockerfile: Dockerfile.alpine-debug
|
||||||
security_opt:
|
security_opt:
|
||||||
- seccomp:unconfined
|
- seccomp:unconfined
|
||||||
cap_add:
|
cap_add:
|
||||||
@ -35,8 +35,10 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./logs:/var/log/grd_login
|
- ./logs:/var/log/grd_login
|
||||||
- ./login_server/src:/code/src
|
- ./login_server/src:/code/src
|
||||||
|
- ./login_server/dependencies:/code/dependencies
|
||||||
|
- ./login_server/scripts:/code/scripts
|
||||||
- ./configs/login_server:/etc/grd_login
|
- ./configs/login_server:/etc/grd_login
|
||||||
- login_build_conan:/code/build_vol
|
- login_build_alpine:/code/build
|
||||||
|
|
||||||
|
|
||||||
#########################################################
|
#########################################################
|
||||||
@ -101,5 +103,4 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
frontend_node_modules:
|
frontend_node_modules:
|
||||||
login_build_conan:
|
login_build_alpine:
|
||||||
|
|
||||||
|
|||||||
@ -24,12 +24,12 @@ Additional session can be provided as GET-Parameter
|
|||||||
{
|
{
|
||||||
"state":"success",
|
"state":"success",
|
||||||
"balance":1590.60,
|
"balance":1590.60,
|
||||||
"decay":15873851,
|
"decay":1587.38,
|
||||||
"decay_date":"2021-04-16T11:47:21+00:00"
|
"decay_date":"2021-04-16T11:47:21+00:00"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `balance` : balance describes gradido
|
- `balance` : balance describes gradido as float with max two decimal places
|
||||||
- `decay` : balance with decay on it at the time in decay_date, so it is the precise balance of user at time of calling this function
|
- `decay` : balance with decay on it at the time in decay_date, so it is the precise balance of user at time of calling this function
|
||||||
- `decay_date`: date and time for decay amount, should be the time and date of function call
|
- `decay_date`: date and time for decay amount, should be the time and date of function call
|
||||||
|
|
||||||
@ -59,6 +59,12 @@ Assuming: session is valid
|
|||||||
{
|
{
|
||||||
"state":"success",
|
"state":"success",
|
||||||
"transactions": [
|
"transactions": [
|
||||||
|
{
|
||||||
|
"type": "decay",
|
||||||
|
"balance": "14.74",
|
||||||
|
"decay_duration": "4 days, 2 hours ago",
|
||||||
|
"memo": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Max Mustermann",
|
"name": "Max Mustermann",
|
||||||
"email": "Maxim Mustermann",
|
"email": "Maxim Mustermann",
|
||||||
@ -68,7 +74,17 @@ Assuming: session is valid
|
|||||||
"balance": 192.0,
|
"balance": 192.0,
|
||||||
"memo": "a piece of cake :)",
|
"memo": "a piece of cake :)",
|
||||||
"pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7"
|
"pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7"
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"name": "Gradido Akademie",
|
||||||
|
"type": "creation",
|
||||||
|
"transaction_id": 10,
|
||||||
|
"date": "2021-04-15T11:19:45+00:00",
|
||||||
|
"target_date": "2021-02-01T00:00:00+00:00",
|
||||||
|
"creation_amount": "1000.0",
|
||||||
|
"balance": "1000.0",
|
||||||
|
"memo": "AGE Februar 2021"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"transactionExecutingCount": 0,
|
"transactionExecutingCount": 0,
|
||||||
"count": 1,
|
"count": 1,
|
||||||
@ -95,8 +111,11 @@ Transaction:
|
|||||||
- `receiver`: user has received gradidos from another user
|
- `receiver`: user has received gradidos from another user
|
||||||
- `transaction_id`: id of transaction in db, in stage2 also the hedera sequence number of transaction
|
- `transaction_id`: id of transaction in db, in stage2 also the hedera sequence number of transaction
|
||||||
- `date`: date of ordering transaction (booking date)
|
- `date`: date of ordering transaction (booking date)
|
||||||
- `balance`: Gradido
|
- `balance`: Gradido as float, max 2 Nachkommastellen, by creation balance after subtract decay amount
|
||||||
- `memo`: Details about transaction
|
- `memo`: Details about transaction
|
||||||
|
- `decay_duration`: only for decay, time duration for decay calculation in english text
|
||||||
|
- `creation_amount`: only for creation transaction, created account before decay
|
||||||
|
- `target_date`: only by creation transaction, target date for creation, start time for decay calculation (if < as global decay start time)
|
||||||
|
|
||||||
## Creation transaction
|
## Creation transaction
|
||||||
Makes a creation transaction to create new Gradido
|
Makes a creation transaction to create new Gradido
|
||||||
@ -117,7 +136,7 @@ with
|
|||||||
{
|
{
|
||||||
"session_id" : -127182,
|
"session_id" : -127182,
|
||||||
"email": "max.musterman@gmail.de",
|
"email": "max.musterman@gmail.de",
|
||||||
"amount": 10000000,
|
"amount": 1000.0,
|
||||||
"target_date":"2021-02-19T13:25:36+00:00",
|
"target_date":"2021-02-19T13:25:36+00:00",
|
||||||
"memo":"AGE",
|
"memo":"AGE",
|
||||||
"auto_sign": true
|
"auto_sign": true
|
||||||
@ -128,7 +147,7 @@ with
|
|||||||
{
|
{
|
||||||
"session_id" : -127182,
|
"session_id" : -127182,
|
||||||
"username": "Maxi_786",
|
"username": "Maxi_786",
|
||||||
"amount": 10000000,
|
"amount": 1000.0,
|
||||||
"target_date":"2021-02-19T13:25:36+00:00",
|
"target_date":"2021-02-19T13:25:36+00:00",
|
||||||
"memo":"AGE",
|
"memo":"AGE",
|
||||||
"auto_sign": true
|
"auto_sign": true
|
||||||
@ -139,7 +158,7 @@ with
|
|||||||
{
|
{
|
||||||
"session_id" : -127182,
|
"session_id" : -127182,
|
||||||
"pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7",
|
"pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7",
|
||||||
"amount": 10000000,
|
"amount": 1000.0,
|
||||||
"target_date":"2021-02-19T13:25:36+00:00",
|
"target_date":"2021-02-19T13:25:36+00:00",
|
||||||
"memo":"AGE",
|
"memo":"AGE",
|
||||||
"auto_sign": true
|
"auto_sign": true
|
||||||
@ -149,8 +168,7 @@ with
|
|||||||
|
|
||||||
- `session_id`: optional, only used if cookie GRADIDO_LOGIN not exist and no sesion_id in php session
|
- `session_id`: optional, only used if cookie GRADIDO_LOGIN not exist and no sesion_id in php session
|
||||||
- `email` or `username` or `pubkey`: used to identify how gets the gradidos (email and username are only aliases for pubkey)
|
- `email` or `username` or `pubkey`: used to identify how gets the gradidos (email and username are only aliases for pubkey)
|
||||||
- `amount`: gdd amount to transfer in gradido cent (10000000 = 1000,00 GDD)
|
- `amount`: gdd amount to transfer in gradido as float
|
||||||
- `target_date`: target date for creation, can be max 3 months before current date, but not after current date, allowed formats do you find here: https://pocoproject.org/docs/Poco.DateTimeFormat.html
|
|
||||||
- `memo`: text for receiver, currently saved as clear text in blockchain
|
- `memo`: text for receiver, currently saved as clear text in blockchain
|
||||||
- `auto_sign`: if set to true, transaction will be directly signed on login-server and proceed if needed signs are there
|
- `auto_sign`: if set to true, transaction will be directly signed on login-server and proceed if needed signs are there
|
||||||
if set to false, transaction must be signed after on `http://localhost/account/checkTransactions`
|
if set to false, transaction must be signed after on `http://localhost/account/checkTransactions`
|
||||||
@ -186,7 +204,7 @@ with
|
|||||||
{
|
{
|
||||||
"session_id" : -127182,
|
"session_id" : -127182,
|
||||||
"email": "max.musterman@gmail.de",
|
"email": "max.musterman@gmail.de",
|
||||||
"amount": 1000000,
|
"amount": 100.0,
|
||||||
"memo":"a gift",
|
"memo":"a gift",
|
||||||
"auto_sign": true
|
"auto_sign": true
|
||||||
}
|
}
|
||||||
@ -196,7 +214,7 @@ with
|
|||||||
{
|
{
|
||||||
"session_id" : -127182,
|
"session_id" : -127182,
|
||||||
"username": "Maxi_786",
|
"username": "Maxi_786",
|
||||||
"amount": 1000000,
|
"amount": 100.0,
|
||||||
"memo":"a gift",
|
"memo":"a gift",
|
||||||
"auto_sign": true
|
"auto_sign": true
|
||||||
}
|
}
|
||||||
@ -206,13 +224,13 @@ with
|
|||||||
{
|
{
|
||||||
"session_id" : -127182,
|
"session_id" : -127182,
|
||||||
"pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7",
|
"pubkey": "038a6f93270dc57b91d76bf110ad3863fcb7d1b08e7692e793fcdb4467e5b6a7",
|
||||||
"amount": 1000000,
|
"amount": 100.0,
|
||||||
"memo":"a gift",
|
"memo":"a gift",
|
||||||
"auto_sign": true
|
"auto_sign": true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- `session_id`: optional, only used if cookie GRADIDO_LOGIN not exist and no sesion_id in php session
|
- `session_id`: optional, only used if cookie GRADIDO_LOGIN not exist and no sesion_id in php session
|
||||||
- `amount`: amount to transfer, 2000000 = 200,00 GDD
|
- `amount`: amount to transfer as float
|
||||||
- `email` or `username` or `pubkey`: used to identify how gets the gradidos (email and username are only aliases for pubkey)
|
- `email` or `username` or `pubkey`: used to identify how gets the gradidos (email and username are only aliases for pubkey)
|
||||||
- `memo`: text for receiver, currently saved as clear text in blockchain
|
- `memo`: text for receiver, currently saved as clear text in blockchain
|
||||||
- `auto_sign`: if set to true, transaction will be directly signed on login-server and proceed if needed signs are there
|
- `auto_sign`: if set to true, transaction will be directly signed on login-server and proceed if needed signs are there
|
||||||
@ -245,3 +263,41 @@ Without auto-sign the transaction is pending on the login-server and waits for t
|
|||||||
// TODO Is this in line with our usability goals?
|
// TODO Is this in line with our usability goals?
|
||||||
// TODO Should this not be handled client side?
|
// TODO Should this not be handled client side?
|
||||||
|
|
||||||
|
|
||||||
|
# Klicktipp
|
||||||
|
|
||||||
|
## Subscribe
|
||||||
|
Subscribe current logged in user to gradido newsletter
|
||||||
|
|
||||||
|
### Request
|
||||||
|
`GET http://localhost/api/klicktipp_subscribe/[session_id]`
|
||||||
|
Parts symbolized by [] are optional
|
||||||
|
- session_id: session will be searched in php session and GRADIDO_LOGIN cookie and if not found use this
|
||||||
|
|
||||||
|
### Response
|
||||||
|
Assuming: session is valid
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"state": "success",
|
||||||
|
"redirect_url": "<redirect url from klicktipp>"
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
## Unsubscribe
|
||||||
|
Unsubscribe current logged in user from gradido newsletter
|
||||||
|
|
||||||
|
### Request
|
||||||
|
`GET http://localhost/api/klicktipp_unsubscribe/[session_id]`
|
||||||
|
Parts symbolized by [] are optional
|
||||||
|
- session_id: session will be searched in php session and GRADIDO_LOGIN cookie and if not found use this
|
||||||
|
|
||||||
|
### Response
|
||||||
|
Assuming: session is valid
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"state": "success"
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
|||||||
30
docu/other/mariadb_groups_insert.md
Normal file
30
docu/other/mariadb_groups_insert.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Das Locale Schöpfen
|
||||||
|
|
||||||
|
### MariaDB Insert Groups
|
||||||
|
|
||||||
|
wenn local geschöpft werden möchte kommt ein fehler das der user keiner gruppe zugeordnet ist.
|
||||||
|
|
||||||
|
folgende schritte musst du machen um eine gruppe anzulegen
|
||||||
|
|
||||||
|
hier findest du den Mysql befehl: configs/login_server/setup_db_tables/setup_docker_group.sql
|
||||||
|
in der Datei findest du folgenden Befehl
|
||||||
|
|
||||||
|
INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `host`, `home`, `description`) VALUES
|
||||||
|
(1, 'docker', 'docker gradido group', 'localhost', 'nginx', '/', 'gradido test group for docker and stage2 with blockchain db');
|
||||||
|
|
||||||
|
# Ablauf
|
||||||
|
|
||||||
|
1. logge dich bei phpmyadmin ein http://localhost:8074/ (mariadb / root)
|
||||||
|
2. gehe auf tabelle "gradido_login"
|
||||||
|
3. gib folgenden Befehl in die console ein
|
||||||
|
|
||||||
|
INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `host`, `home`, `description`) VALUES
|
||||||
|
(1, 'docker', 'docker gradido group', 'localhost', 'nginx', '/', 'gradido test group for docker and stage2 with blockchain db');
|
||||||
|
|
||||||
|
> es wird eine Gruppe mit id 1 angelgt. alle angelegten user sollten dieser gruppe zugeordnet sein.
|
||||||
|
|
||||||
|
das schöpfen sollte nun local funktionieren. :)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ACHTUNG ! nach dem login kann noch zu fehlern kommen in der URL "localhostnginx/..." zu "localhost/..." ändern
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bootstrap-vue-gradido-wallet",
|
"name": "bootstrap-vue-gradido-wallet",
|
||||||
"version": "0.9.4",
|
"version": "1.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node run/server.js",
|
"start": "node run/server.js",
|
||||||
|
|||||||
@ -1,20 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app" class="font-sans text-gray-800">
|
<div id="app" class="font-sans text-gray-800">
|
||||||
<header>
|
|
||||||
<b-col class="text-center">
|
|
||||||
<b-dropdown
|
|
||||||
size="sm"
|
|
||||||
split
|
|
||||||
variant="secondary"
|
|
||||||
:text="$t('language') + ' - ' + $i18n.locale"
|
|
||||||
class="m-md-2"
|
|
||||||
>
|
|
||||||
<b-dropdown-divider></b-dropdown-divider>
|
|
||||||
<b-dropdown-item @click.prevent="setLocale('de')">Deutsch</b-dropdown-item>
|
|
||||||
<b-dropdown-item @click.prevent="setLocale('en')">English</b-dropdown-item>
|
|
||||||
</b-dropdown>
|
|
||||||
</b-col>
|
|
||||||
</header>
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<particles-bg type="custom" :config="config" :bg="true" />
|
<particles-bg type="custom" :config="config" :bg="true" />
|
||||||
<component :is="$route.meta.requiresAuth ? 'DashboardLayout' : 'AuthLayoutGDD'" />
|
<component :is="$route.meta.requiresAuth ? 'DashboardLayout' : 'AuthLayoutGDD'" />
|
||||||
@ -25,7 +10,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { ParticlesBg } from 'particles-bg-vue'
|
import { ParticlesBg } from 'particles-bg-vue'
|
||||||
import icon from './icon.js'
|
import icon from './icon.js'
|
||||||
import { localeChanged } from 'vee-validate'
|
|
||||||
import DashboardLayout from '@/views/Layout/DashboardLayout_gdd.vue'
|
import DashboardLayout from '@/views/Layout/DashboardLayout_gdd.vue'
|
||||||
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
|
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
|
||||||
|
|
||||||
@ -54,13 +38,6 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
setLocale(locale) {
|
|
||||||
this.$i18n.locale = locale
|
|
||||||
this.$store.commit('language', this.$i18n.locale)
|
|
||||||
localeChanged(locale)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -35,7 +35,7 @@ const communityAPI = {
|
|||||||
balance: async (sessionId) => {
|
balance: async (sessionId) => {
|
||||||
return apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId)
|
return apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId)
|
||||||
},
|
},
|
||||||
transactions: async (sessionId, firstPage = 1, items = 25, order = 'DESC') => {
|
transactions: async (sessionId, firstPage = 1, items = 1000, order = 'DESC') => {
|
||||||
return apiGet(
|
return apiGet(
|
||||||
`${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${sessionId}`,
|
`${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${sessionId}`,
|
||||||
)
|
)
|
||||||
@ -51,14 +51,11 @@ const communityAPI = {
|
|||||||
}
|
}
|
||||||
return apiPost(CONFIG.COMMUNITY_API__URL + 'createCoins/', payload)
|
return apiPost(CONFIG.COMMUNITY_API__URL + 'createCoins/', payload)
|
||||||
}, */
|
}, */
|
||||||
send: async (sessionId, email, amount, memo, targetDate) => {
|
send: async (sessionId, data) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
email,
|
|
||||||
amount,
|
|
||||||
memo,
|
|
||||||
target_date: targetDate,
|
|
||||||
auto_sign: true,
|
auto_sign: true,
|
||||||
|
...data,
|
||||||
}
|
}
|
||||||
return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload)
|
return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import CONFIG from '../config'
|
import CONFIG from '../config'
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import regeneratorRuntime from 'regenerator-runtime'
|
||||||
|
|
||||||
// control email-text sended with email verification code
|
// control email-text sended with email verification code
|
||||||
const EMAIL_TYPE = {
|
const EMAIL_TYPE = {
|
||||||
@ -86,6 +88,16 @@ const loginAPI = {
|
|||||||
}
|
}
|
||||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||||
},
|
},
|
||||||
|
updateLanguage: async (sessionId, email, language) => {
|
||||||
|
const payload = {
|
||||||
|
session_id: sessionId,
|
||||||
|
email,
|
||||||
|
update: {
|
||||||
|
'User.language': language,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default loginAPI
|
export default loginAPI
|
||||||
|
|||||||
95
frontend/src/components/LanguageSwitch.spec.js
Normal file
95
frontend/src/components/LanguageSwitch.spec.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import LanguageSwitch from './LanguageSwitch'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
describe('LanguageSwitch', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
sessionId: 1234,
|
||||||
|
email: 'he@ho.he',
|
||||||
|
language: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$store: {
|
||||||
|
state,
|
||||||
|
commit: jest.fn(),
|
||||||
|
},
|
||||||
|
$i18n: {
|
||||||
|
locale: 'en',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(LanguageSwitch, { localVue, mocks })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component', () => {
|
||||||
|
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with locales en and de', () => {
|
||||||
|
describe('empty store', () => {
|
||||||
|
it('shows English as default navigator langauge', () => {
|
||||||
|
expect(wrapper.find('button.dropdown-toggle').text()).toBe('English - en')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('navigator language is "de-DE"', () => {
|
||||||
|
const mockNavigator = jest.fn(() => {
|
||||||
|
return 'de'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows Deutsch as language ', async () => {
|
||||||
|
wrapper.vm.getNavigatorLanguage = mockNavigator
|
||||||
|
wrapper.vm.setCurrentLanguage()
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.find('button.dropdown-toggle').text()).toBe('Deutsch - de')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('navigator language is "es-ES" (not supported)', () => {
|
||||||
|
const mockNavigator = jest.fn(() => {
|
||||||
|
return 'es'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows English as language ', async () => {
|
||||||
|
wrapper.vm.getNavigatorLanguage = mockNavigator
|
||||||
|
wrapper.vm.setCurrentLanguage()
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.find('button.dropdown-toggle').text()).toBe('English - en')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('language "de" in store', () => {
|
||||||
|
it('shows Deutsch as language', async () => {
|
||||||
|
wrapper.vm.$store.state.language = 'de'
|
||||||
|
wrapper.vm.setCurrentLanguage()
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.find('button.dropdown-toggle').text()).toBe('Deutsch - de')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('dropdown menu', () => {
|
||||||
|
it('has English and German as languages to choose', () => {
|
||||||
|
expect(wrapper.findAll('li')).toHaveLength(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has English as first language to choose', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).text()).toBe('English')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has German as second language to choose', () => {
|
||||||
|
expect(wrapper.findAll('li').at(1).text()).toBe('Deutsch')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
72
frontend/src/components/LanguageSwitch.vue
Normal file
72
frontend/src/components/LanguageSwitch.vue
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<div class="language-switch">
|
||||||
|
<b-dropdown size="sm" :text="currentLanguage.name + ' - ' + currentLanguage.code">
|
||||||
|
<b-dropdown-item
|
||||||
|
v-for="lang in locales"
|
||||||
|
@click.prevent="saveLocale(lang.code)"
|
||||||
|
:key="lang.code"
|
||||||
|
>
|
||||||
|
{{ lang.name }}
|
||||||
|
</b-dropdown-item>
|
||||||
|
</b-dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { localeChanged } from 'vee-validate'
|
||||||
|
import locales from '../locales/'
|
||||||
|
import loginAPI from '../apis/loginAPI'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LanguageSwitch',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
locales: locales,
|
||||||
|
currentLanguage: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setLocale(locale) {
|
||||||
|
this.$i18n.locale = locale
|
||||||
|
this.$store.commit('language', this.$i18n.locale)
|
||||||
|
this.currentLanguage = this.getLocaleObject(locale)
|
||||||
|
localeChanged(locale)
|
||||||
|
},
|
||||||
|
async saveLocale(locale) {
|
||||||
|
this.setLocale(locale)
|
||||||
|
if (this.$store.state.sessionId && this.$store.state.email) {
|
||||||
|
const result = await loginAPI.updateLanguage(
|
||||||
|
this.$store.state.sessionId,
|
||||||
|
this.$store.state.email,
|
||||||
|
locale,
|
||||||
|
)
|
||||||
|
if (result.success) {
|
||||||
|
// toast success message
|
||||||
|
} else {
|
||||||
|
// toast error message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getLocaleObject(code) {
|
||||||
|
return this.locales.find((l) => l.code === code)
|
||||||
|
},
|
||||||
|
getNavigatorLanguage() {
|
||||||
|
const lang = navigator.language
|
||||||
|
if (lang) return lang.split('-')[0]
|
||||||
|
return lang
|
||||||
|
},
|
||||||
|
setCurrentLanguage() {
|
||||||
|
let locale = this.$store.state.language || this.getNavigatorLanguage() || 'en'
|
||||||
|
let object = this.getLocaleObject(locale)
|
||||||
|
if (!object) {
|
||||||
|
locale = 'en'
|
||||||
|
object = this.getLocaleObject(locale)
|
||||||
|
}
|
||||||
|
this.setLocale(locale)
|
||||||
|
this.currentLanguage = object
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.setCurrentLanguage()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
124
frontend/src/components/SidebarPlugin/SideBar.spec.js
Normal file
124
frontend/src/components/SidebarPlugin/SideBar.spec.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||||
|
import SideBar from './SideBar'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
describe('SideBar', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const stubs = {
|
||||||
|
RouterLink: RouterLinkStub,
|
||||||
|
}
|
||||||
|
|
||||||
|
const propsData = {
|
||||||
|
balance: 1234.56,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
email: 'test@example.org',
|
||||||
|
},
|
||||||
|
commit: jest.fn(),
|
||||||
|
},
|
||||||
|
$i18n: {
|
||||||
|
locale: 'en',
|
||||||
|
},
|
||||||
|
$t: jest.fn((t) => t),
|
||||||
|
$n: jest.fn((n) => n),
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(SideBar, { localVue, mocks, stubs, propsData })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component', () => {
|
||||||
|
expect(wrapper.find('#sidenav-main').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('balance', () => {
|
||||||
|
it('shows em-dash as balance while loading', () => {
|
||||||
|
expect(wrapper.find('div.row.text-center').text()).toBe('— GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the when loaded', async () => {
|
||||||
|
wrapper.setProps({
|
||||||
|
pending: false,
|
||||||
|
})
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.find('div.row.text-center').text()).toBe('1234.56 GDD')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('navbar button', () => {
|
||||||
|
it('has a navbar button', () => {
|
||||||
|
expect(wrapper.find('button.navbar-toggler').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls showSidebar when clicked', async () => {
|
||||||
|
const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar')
|
||||||
|
wrapper.find('button.navbar-toggler').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(spy).toHaveBeenCalledWith(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('close siedbar', () => {
|
||||||
|
it('calls closeSidebar when clicked', async () => {
|
||||||
|
const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar')
|
||||||
|
wrapper.find('#sidenav-collapse-main').find('button.navbar-toggler').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(spy).toHaveBeenCalledWith(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('static menu items', () => {
|
||||||
|
describe("member's area", () => {
|
||||||
|
it('has a link to the elopage', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).text()).toBe('members_area')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('links to the elopage', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe(
|
||||||
|
'https://elopage.com/s/gradido/sign_in?locale=en',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with locale="de"', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks.$i18n.locale = 'de'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('links to the German elopage when locale is set to de', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe(
|
||||||
|
'https://elopage.com/s/gradido/sign_in?locale=de',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('logout', () => {
|
||||||
|
it('has a logout button', () => {
|
||||||
|
expect(wrapper.findAll('li').at(1).text()).toBe('logout')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits logout when logout is clicked', async () => {
|
||||||
|
wrapper.findAll('li').at(1).find('a').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.emitted('logout')).toEqual([[]])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('language-switch', () => {
|
||||||
|
it('has a language-switch button', () => {
|
||||||
|
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<img :src="logo" class="navbar-brand-img" alt="..." />
|
<img :src="logo" class="navbar-brand-img" alt="..." />
|
||||||
</div>
|
</div>
|
||||||
<b-row class="text-center">
|
<b-row class="text-center">
|
||||||
<b-col>{{ $n(balance) }} GDD</b-col>
|
<b-col>{{ pending ? '—' : $n(balance) }} GDD</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<slot name="mobile-right">
|
<slot name="mobile-right">
|
||||||
<ul class="nav align-items-center d-md-none">
|
<ul class="nav align-items-center d-md-none">
|
||||||
@ -32,9 +32,7 @@
|
|||||||
<div class="navbar-collapse-header d-md-none">
|
<div class="navbar-collapse-header d-md-none">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 collapse-brand">
|
<div class="col-6 collapse-brand">
|
||||||
<router-link to="/overview">
|
<img :src="logo" />
|
||||||
<img :src="logo" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 collapse-close">
|
<div class="col-6 collapse-close">
|
||||||
<navbar-toggle-button @click.native="closeSidebar"></navbar-toggle-button>
|
<navbar-toggle-button @click.native="closeSidebar"></navbar-toggle-button>
|
||||||
@ -44,26 +42,29 @@
|
|||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<slot name="links"></slot>
|
<slot name="links"></slot>
|
||||||
</ul>
|
</ul>
|
||||||
<hr class="my-3" />
|
<hr class="my-2" />
|
||||||
<ul class="navbar-nav mb-md-3">
|
<ul class="navbar-nav ml-3">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a
|
<a
|
||||||
:href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
|
:href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
|
||||||
class="nav-link text-lg"
|
class="nav-link"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{{ $t('members_area') }}
|
{{ $t('members_area') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr class="my-3" />
|
|
||||||
<ul class="navbar-nav mb-md-3">
|
<ul class="navbar-nav ml-3">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link text-lg pointer" @click="logout">
|
<a class="nav-link pointer" @click="logout">
|
||||||
{{ $t('logout') }}
|
{{ $t('logout') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="mt-5 ml-4">
|
||||||
|
<language-switch />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -71,12 +72,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import NavbarToggleButton from '@/components/NavbarToggleButton'
|
import NavbarToggleButton from '@/components/NavbarToggleButton'
|
||||||
import VueQrcode from 'vue-qrcode'
|
import VueQrcode from 'vue-qrcode'
|
||||||
|
import LanguageSwitch from '@/components/LanguageSwitch.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'sidebar',
|
name: 'sidebar',
|
||||||
components: {
|
components: {
|
||||||
NavbarToggleButton,
|
NavbarToggleButton,
|
||||||
VueQrcode,
|
VueQrcode,
|
||||||
|
LanguageSwitch,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
logo: {
|
logo: {
|
||||||
@ -84,6 +87,7 @@ export default {
|
|||||||
default: 'img/brand/green.png',
|
default: 'img/brand/green.png',
|
||||||
description: 'Gradido Sidebar app logo',
|
description: 'Gradido Sidebar app logo',
|
||||||
},
|
},
|
||||||
|
value: { type: Array },
|
||||||
autoClose: {
|
autoClose: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
@ -93,6 +97,10 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
pending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"welcome":"Willkommen!",
|
"welcome":"Willkommen!",
|
||||||
"community": "Gemeinschaft",
|
"community": "Gemeinschaft",
|
||||||
"logout":"Abmelden",
|
"logout":"Abmelden",
|
||||||
"login":"Login",
|
"login":"Anmeldung",
|
||||||
"signup": "Registrieren",
|
"signup": "Registrieren",
|
||||||
"reset": "Passwort zurücksetzen",
|
"reset": "Passwort zurücksetzen",
|
||||||
"imprint":"Impressum",
|
"imprint":"Impressum",
|
||||||
@ -13,13 +13,12 @@
|
|||||||
"back":"Zurück",
|
"back":"Zurück",
|
||||||
"send":"Senden",
|
"send":"Senden",
|
||||||
"transactions":"Transaktionen",
|
"transactions":"Transaktionen",
|
||||||
"language":"Language",
|
"language":"Sprache",
|
||||||
"languages":{
|
"languages":{
|
||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
"en": "English"
|
"en": "English"
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"attention": "<strong>Achtung!</strong> Bitte überprüfe alle deine Eingaben sehr genau. Du bist alleine Verantwortlich für deine Entscheidungen. Versendete Gradidos können nicht wieder zurück geholt werden.",
|
|
||||||
"cancel":"Abbrechen",
|
"cancel":"Abbrechen",
|
||||||
"reset": "Zurücksetzen",
|
"reset": "Zurücksetzen",
|
||||||
"close":"schließen",
|
"close":"schließen",
|
||||||
@ -41,10 +40,16 @@
|
|||||||
"time":"Zeit",
|
"time":"Zeit",
|
||||||
"send_now":"Jetzt versenden",
|
"send_now":"Jetzt versenden",
|
||||||
"scann_code":"<strong>QR Code Scanner</strong> - Scanne den QR Code deines Partners",
|
"scann_code":"<strong>QR Code Scanner</strong> - Scanne den QR Code deines Partners",
|
||||||
"max_gdd_info":"maximale anzahl GDD zum versenden erreicht!",
|
"max_gdd_info":"Maximale anzahl GDD zum versenden erreicht!",
|
||||||
"send_check":"Bestätige deine Zahlung. Prüfe bitte nochmal alle Daten!",
|
"send_check":"Bestätige deine Zahlung. Prüfe bitte nochmal alle Daten!",
|
||||||
"thx":"Danke,",
|
"thx":"Danke",
|
||||||
"send_success":"deine Transaktion wurde erfolgreich ausgeführt"
|
"sorry":"Entschuldigung",
|
||||||
|
"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",
|
||||||
|
"is-not": "Du kannst dir selbst keine Gradidos überweisen"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"error":"Fehler"
|
"error":"Fehler"
|
||||||
@ -79,7 +84,9 @@
|
|||||||
},
|
},
|
||||||
"thx": {
|
"thx": {
|
||||||
"title": "Danke!",
|
"title": "Danke!",
|
||||||
"subtitle": "Wir haben dir eine eMail gesendet."
|
"email": "Wir haben dir eine eMail gesendet.",
|
||||||
|
"reset": "Dein Passwort wurde geändert.",
|
||||||
|
"register": "Du bist jetzt regisriert."
|
||||||
},
|
},
|
||||||
"overview":{
|
"overview":{
|
||||||
"account_overview":"Kontoübersicht",
|
"account_overview":"Kontoübersicht",
|
||||||
@ -117,7 +124,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reset-password": {
|
"reset-password": {
|
||||||
"title": "Passwort Zurücksetzen",
|
"title": "Passwort zurücksetzen",
|
||||||
"text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünfitg in der GRADIDO App anmelden kannst."
|
"text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,13 +13,12 @@
|
|||||||
"back":"Back",
|
"back":"Back",
|
||||||
"send":"Send",
|
"send":"Send",
|
||||||
"transactions":"Transactions",
|
"transactions":"Transactions",
|
||||||
"language":"Sprache",
|
"language":"Language",
|
||||||
"languages":{
|
"languages":{
|
||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
"en": "English"
|
"en": "English"
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"attention": "Achtung! Bitte überprüfe alle deine Eingaben sehr genau. Du bist alleine Verantwortlich für deine Entscheidungen. Versendete Gradidos können nicht wieder zurück geholt werden.",
|
|
||||||
"cancel":"Cancel",
|
"cancel":"Cancel",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"close":"Close",
|
"close":"Close",
|
||||||
@ -40,18 +39,23 @@
|
|||||||
"at":"at",
|
"at":"at",
|
||||||
"time":"Time",
|
"time":"Time",
|
||||||
"send_now":"Send now",
|
"send_now":"Send now",
|
||||||
"scann_code":"<strong>QR Code Scanner</strong> - Scanne den QR Code deines Partners",
|
"scann_code":"<strong>QR Code Scanner</strong> - Scan the QR Code of your partner",
|
||||||
"max_gdd_info":"maximale anzahl GDD zum versenden erreicht!",
|
"max_gdd_info":"Maximum number of GDDs to be sent has been reached!",
|
||||||
"send_check":"Bestätige deine Zahlung. Prüfe bitte nochmal alle Daten!",
|
"send_check":"Confirm your payment. Please check all data again!",
|
||||||
"thx":"Thank you,",
|
"thx":"Thank you",
|
||||||
"send_success":"your transaction was successfully completed"
|
"sorry":"Sorry",
|
||||||
|
"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",
|
||||||
|
"is-not": "You cannot send Gradidos to yourself"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"error":"Error"
|
"error":"Error"
|
||||||
},
|
},
|
||||||
"transaction":{
|
"transaction":{
|
||||||
"show_all":"View all <strong>{count}</strong> transactions.",
|
"show_all":"View all <strong>{count}</strong> transactions.",
|
||||||
"show_part": "The last <strong>{count}</strong> transactions.",
|
|
||||||
"nullTransactions":"You don't have any transactions on your account yet.",
|
"nullTransactions":"You don't have any transactions on your account yet.",
|
||||||
"more": "more"
|
"more": "more"
|
||||||
},
|
},
|
||||||
@ -80,7 +84,9 @@
|
|||||||
},
|
},
|
||||||
"thx": {
|
"thx": {
|
||||||
"title": "Thank you!",
|
"title": "Thank you!",
|
||||||
"subtitle": "We have sent you an email."
|
"email": "We have sent you an email.",
|
||||||
|
"reset": "Your password has been changed.",
|
||||||
|
"register": "You are registred now."
|
||||||
},
|
},
|
||||||
"overview":{
|
"overview":{
|
||||||
"account_overview":"Account overview",
|
"account_overview":"Account overview",
|
||||||
@ -119,6 +125,6 @@
|
|||||||
},
|
},
|
||||||
"reset-password": {
|
"reset-password": {
|
||||||
"title": "Reset Password",
|
"title": "Reset Password",
|
||||||
"text": "Now you can save a new password to login to the GRADIDO App in the future."
|
"text": "Now you can save a new password to login to the Gradido-App in the future."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
frontend/src/locales/index.js
Normal file
16
frontend/src/locales/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const locales = [
|
||||||
|
{
|
||||||
|
name: 'English',
|
||||||
|
code: 'en',
|
||||||
|
iso: 'en-US',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Deutsch',
|
||||||
|
code: 'de',
|
||||||
|
iso: 'de-DE',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default locales
|
||||||
@ -2,6 +2,9 @@ import Vue from 'vue'
|
|||||||
import DashboardPlugin from './plugins/dashboard-plugin'
|
import DashboardPlugin from './plugins/dashboard-plugin'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import i18n from './i18n.js'
|
import i18n from './i18n.js'
|
||||||
|
import { configure, extend } from 'vee-validate'
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
import { required, email, min, between, double, is_not } from 'vee-validate/dist/rules'
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { store } from './store/store'
|
import { store } from './store/store'
|
||||||
@ -21,6 +24,45 @@ router.beforeEach((to, from, next) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
configure({
|
||||||
|
defaultMessage: (field, values) => {
|
||||||
|
values._field_ = i18n.t(`fields.${field}`)
|
||||||
|
return i18n.t(`validations.messages.${values._rule_}`, values)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
extend('email', {
|
||||||
|
...email,
|
||||||
|
message: (_, values) => i18n.t('validations.messages.email', values),
|
||||||
|
})
|
||||||
|
|
||||||
|
extend('required', {
|
||||||
|
...required,
|
||||||
|
message: (_, values) => i18n.t('validations.messages.required', values),
|
||||||
|
})
|
||||||
|
|
||||||
|
extend('min', {
|
||||||
|
...min,
|
||||||
|
message: (_, values) => i18n.t('validations.messages.min', values),
|
||||||
|
})
|
||||||
|
|
||||||
|
extend('double', {
|
||||||
|
...double,
|
||||||
|
message: (_, values) => i18n.t('form.validation.double', values),
|
||||||
|
})
|
||||||
|
|
||||||
|
extend('between', {
|
||||||
|
...between,
|
||||||
|
message: (_, values) => i18n.t('validations.messages.between', values),
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
extend('is_not', {
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
...is_not,
|
||||||
|
message: (_, values) => i18n.t('form.validation.is-not', values),
|
||||||
|
})
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
/* eslint-disable no-new */
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
|
|||||||
@ -47,8 +47,16 @@ const routes = [
|
|||||||
component: () => import('../views/Pages/Login.vue'),
|
component: () => import('../views/Pages/Login.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/thx',
|
path: '/thx/:comingFrom',
|
||||||
component: () => import('../views/Pages/thx.vue'),
|
component: () => import('../views/Pages/thx.vue'),
|
||||||
|
beforeEnter: (to, from, next) => {
|
||||||
|
const validFrom = ['password', 'reset', 'register']
|
||||||
|
if (!validFrom.includes(from.path.split('/')[1])) {
|
||||||
|
next({ path: '/login' })
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/password',
|
path: '/password',
|
||||||
|
|||||||
@ -18,7 +18,8 @@ export const mutations = {
|
|||||||
export const actions = {
|
export const actions = {
|
||||||
login: ({ dispatch, commit }, data) => {
|
login: ({ dispatch, commit }, data) => {
|
||||||
commit('sessionId', data.sessionId)
|
commit('sessionId', data.sessionId)
|
||||||
commit('email', data.email)
|
commit('email', data.user.email)
|
||||||
|
commit('language', data.user.language)
|
||||||
},
|
},
|
||||||
logout: ({ commit, state }) => {
|
logout: ({ commit, state }) => {
|
||||||
commit('sessionId', null)
|
commit('sessionId', null)
|
||||||
@ -36,7 +37,7 @@ export const store = new Vuex.Store({
|
|||||||
state: {
|
state: {
|
||||||
sessionId: null,
|
sessionId: null,
|
||||||
email: '',
|
email: '',
|
||||||
language: 'en',
|
language: null,
|
||||||
modals: false,
|
modals: false,
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
|
|||||||
@ -35,20 +35,37 @@ describe('Vuex store', () => {
|
|||||||
const commit = jest.fn()
|
const commit = jest.fn()
|
||||||
const state = {}
|
const state = {}
|
||||||
|
|
||||||
it('calls two commits', () => {
|
it('calls three commits', () => {
|
||||||
login({ commit, state }, { sessionId: 1234, email: 'someone@there.is' })
|
login(
|
||||||
expect(commit).toHaveBeenCalledTimes(2)
|
{ commit, state },
|
||||||
|
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||||
|
)
|
||||||
|
expect(commit).toHaveBeenCalledTimes(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits sessionId', () => {
|
it('commits sessionId', () => {
|
||||||
login({ commit, state }, { sessionId: 1234, email: 'someone@there.is' })
|
login(
|
||||||
|
{ commit, state },
|
||||||
|
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||||
|
)
|
||||||
expect(commit).toHaveBeenNthCalledWith(1, 'sessionId', 1234)
|
expect(commit).toHaveBeenNthCalledWith(1, 'sessionId', 1234)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits email', () => {
|
it('commits email', () => {
|
||||||
login({ commit, state }, { sessionId: 1234, email: 'someone@there.is' })
|
login(
|
||||||
|
{ commit, state },
|
||||||
|
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||||
|
)
|
||||||
expect(commit).toHaveBeenNthCalledWith(2, 'email', 'someone@there.is')
|
expect(commit).toHaveBeenNthCalledWith(2, 'email', 'someone@there.is')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('commits language', () => {
|
||||||
|
login(
|
||||||
|
{ commit, state },
|
||||||
|
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||||
|
)
|
||||||
|
expect(commit).toHaveBeenNthCalledWith(3, 'language', 'en')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('logout', () => {
|
describe('logout', () => {
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
import { configure, extend } from 'vee-validate'
|
|
||||||
import { required, email, min } from 'vee-validate/dist/rules'
|
|
||||||
import i18n from './i18n'
|
|
||||||
|
|
||||||
configure({
|
|
||||||
defaultMessage: (field, values) => {
|
|
||||||
values._field_ = i18n.t(`fields.${field}`)
|
|
||||||
return i18n.t(`validations.messages.${values._rule_}`, values)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
extend('email', {
|
|
||||||
...email,
|
|
||||||
message: (_, values) => i18n.t('validations.messages.email', values),
|
|
||||||
})
|
|
||||||
|
|
||||||
extend('required', {
|
|
||||||
...required,
|
|
||||||
message: (_, values) => i18n.t('validations.messages.required', values),
|
|
||||||
})
|
|
||||||
|
|
||||||
extend('min', {
|
|
||||||
...min,
|
|
||||||
message: (_, values) => i18n.t('validations.messages.min', values),
|
|
||||||
})
|
|
||||||
@ -1,16 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="main-content">
|
<div class="main-content mt-4">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
|
<language-switch class="text-center mb-5 mt-5" />
|
||||||
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
|
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import ContentFooter from './ContentFooter.vue'
|
import ContentFooter from './ContentFooter.vue'
|
||||||
|
import LanguageSwitch from '@/components/LanguageSwitch.vue'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ContentFooter,
|
ContentFooter,
|
||||||
|
LanguageSwitch,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -44,6 +44,9 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
state,
|
state,
|
||||||
|
mutations: {
|
||||||
|
language: jest.fn(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
@ -59,10 +62,6 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
expect(wrapper.find('nav#sidenav-main').exists()).toBeTruthy()
|
expect(wrapper.find('nav#sidenav-main').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has a notifications component', () => {
|
|
||||||
expect(wrapper.find('div.notifications').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a main content div', () => {
|
it('has a main content div', () => {
|
||||||
expect(wrapper.find('div.main-content').exists()).toBeTruthy()
|
expect(wrapper.find('div.main-content').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
@ -79,31 +78,35 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('has five items in the navbar', () => {
|
it('has five items in the navbar', () => {
|
||||||
expect(navbar.findAll('ul > li')).toHaveLength(2)
|
expect(navbar.findAll('ul > a')).toHaveLength(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has first item "send" in navbar', () => {
|
it('has first item "send" in navbar', () => {
|
||||||
expect(navbar.findAll('ul > li').at(0).text()).toEqual('send')
|
expect(navbar.findAll('ul > a').at(0).text()).toEqual('send')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has first item "send" linked to overview in navbar', () => {
|
it('has first item "send" linked to overview in navbar', () => {
|
||||||
navbar.findAll('ul > li').at(0).trigger('click')
|
navbar.findAll('ul > a').at(0).trigger('click')
|
||||||
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/overview')
|
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/overview')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has second item "transactions" in navbar', () => {
|
it('has second item "transactions" in navbar', () => {
|
||||||
expect(navbar.findAll('ul > li').at(1).text()).toEqual('transactions')
|
expect(navbar.findAll('ul > a').at(1).text()).toEqual('transactions')
|
||||||
})
|
})
|
||||||
|
|
||||||
// to do: get this working!
|
// to do: get this working!
|
||||||
it.skip('has second item "transactions" linked to transactions in navbar', async () => {
|
it.skip('has second item "transactions" linked to transactions in navbar', async () => {
|
||||||
navbar.findAll('ul > li > a').at(1).trigger('click')
|
navbar.findAll('ul > a').at(1).trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
await jest.runAllTimers()
|
await jest.runAllTimers()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/transactions')
|
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/transactions')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// it('has tree items in the navbar', () => {
|
||||||
|
// expect(navbar.findAll('ul > li')).toHaveLength(3)
|
||||||
|
// })
|
||||||
|
//
|
||||||
// it('has third item "My profile" in navbar', () => {
|
// it('has third item "My profile" in navbar', () => {
|
||||||
// expect(navbar.findAll('ul > li').at(2).text()).toEqual('site.navbar.my-profil')
|
// expect(navbar.findAll('ul > li').at(2).text()).toEqual('site.navbar.my-profil')
|
||||||
// })
|
// })
|
||||||
|
|||||||
@ -1,30 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<notifications></notifications>
|
<side-bar @logout="logout" :balance="balance" :pending="pending">
|
||||||
<side-bar @logout="logout" :balance="balance">
|
|
||||||
<template slot="links">
|
<template slot="links">
|
||||||
<b-nav-item href="#!" to="/overview">
|
<sidebar-item
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('send') }}</b-nav-text>
|
:link="{
|
||||||
</b-nav-item>
|
name: $t('send'),
|
||||||
<b-nav-item href="#!" to="/transactions">
|
path: '/overview',
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('transactions') }}</b-nav-text>
|
}"
|
||||||
</b-nav-item>
|
></sidebar-item>
|
||||||
|
<sidebar-item
|
||||||
|
:link="{
|
||||||
|
name: $t('transactions'),
|
||||||
|
path: '/transactions',
|
||||||
|
}"
|
||||||
|
></sidebar-item>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<b-nav-item href="#!" to="/profile">
|
<b-nav-item href="#!" to="/profile">
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
|
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
<b-nav-item href="#!" to="/profileedit">
|
<b-nav-item href="#!" to="/profileedit">
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
|
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
<b-nav-item href="#!" to="/activity">
|
<b-nav-item href="#!" to="/activity">
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
|
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
-->
|
-->
|
||||||
</template>
|
</template>
|
||||||
</side-bar>
|
</side-bar>
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<dashboard-navbar :type="$route.meta.navbarType"></dashboard-navbar>
|
<dashboard-navbar :type="$route.meta.navbarType"></dashboard-navbar>
|
||||||
|
|
||||||
<div @click="$sidebar.displaySidebar(false)">
|
<div @click="$sidebar.displaySidebar(false)">
|
||||||
<fade-transition :duration="200" origin="center top" mode="out-in">
|
<fade-transition :duration="200" origin="center top" mode="out-in">
|
||||||
<!-- your content here -->
|
<!-- your content here -->
|
||||||
@ -33,6 +38,7 @@
|
|||||||
:gdt-balance="GdtBalance"
|
:gdt-balance="GdtBalance"
|
||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:transactionCount="transactionCount"
|
:transactionCount="transactionCount"
|
||||||
|
:pending="pending"
|
||||||
@update-balance="updateBalance"
|
@update-balance="updateBalance"
|
||||||
@update-transactions="updateTransactions"
|
@update-transactions="updateTransactions"
|
||||||
></router-view>
|
></router-view>
|
||||||
@ -83,6 +89,7 @@ export default {
|
|||||||
transactions: [],
|
transactions: [],
|
||||||
bookedBalance: 0,
|
bookedBalance: 0,
|
||||||
transactionCount: 0,
|
transactionCount: 0,
|
||||||
|
pending: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -95,10 +102,12 @@ export default {
|
|||||||
async logout() {
|
async logout() {
|
||||||
await loginAPI.logout(this.$store.state.sessionId)
|
await loginAPI.logout(this.$store.state.sessionId)
|
||||||
// do we have to check success?
|
// do we have to check success?
|
||||||
|
this.$sidebar.displaySidebar(false)
|
||||||
this.$store.dispatch('logout')
|
this.$store.dispatch('logout')
|
||||||
this.$router.push('/login')
|
this.$router.push('/login')
|
||||||
},
|
},
|
||||||
async updateTransactions() {
|
async updateTransactions() {
|
||||||
|
this.pending = true
|
||||||
const result = await communityAPI.transactions(this.$store.state.sessionId)
|
const result = await communityAPI.transactions(this.$store.state.sessionId)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.GdtBalance = Number(result.result.data.gdtSum)
|
this.GdtBalance = Number(result.result.data.gdtSum)
|
||||||
@ -106,7 +115,9 @@ export default {
|
|||||||
this.balance = Number(result.result.data.decay)
|
this.balance = Number(result.result.data.decay)
|
||||||
this.bookedBalance = Number(result.result.data.balance)
|
this.bookedBalance = Number(result.result.data.balance)
|
||||||
this.transactionCount = result.result.data.count
|
this.transactionCount = result.result.data.count
|
||||||
|
this.pending = false
|
||||||
} else {
|
} else {
|
||||||
|
this.pending = true
|
||||||
// what to do when loading balance fails?
|
// what to do when loading balance fails?
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -10,18 +10,18 @@
|
|||||||
<li class="nav-item d-sm-none"></li>
|
<li class="nav-item d-sm-none"></li>
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
<b-navbar-nav class="align-items-center ml-auto ml-md-0">
|
<b-navbar-nav class="align-items-center ml-auto ml-md-0">
|
||||||
<a class="pr-1 nav-link" slot="title-container pointer">
|
<div class="pr-1" slot="title-container ">
|
||||||
<b-media no-body class="align-items-center">
|
<b-media no-body class="align-items-center">
|
||||||
<span class="pb-2 text-lg font-weight-bold">
|
<span class="pb-2 text-lg font-weight-bold">
|
||||||
{{ $store.state.email }}
|
{{ $store.state.email }}
|
||||||
</span>
|
</span>
|
||||||
<b-media-body class="ml-2 d-none d-lg-block">
|
<b-media-body class="ml-2 d-none d-lg-block d-md-block">
|
||||||
<span class="avatar">
|
<span class="avatar">
|
||||||
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
|
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
|
||||||
</span>
|
</span>
|
||||||
</b-media-body>
|
</b-media-body>
|
||||||
</b-media>
|
</b-media>
|
||||||
</a>
|
</div>
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
</base-nav>
|
</base-nav>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -19,10 +19,6 @@ describe('AccountOverview', () => {
|
|||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has a header', () => {
|
|
||||||
expect(wrapper.find('base-header-stub').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a status line', () => {
|
it('has a status line', () => {
|
||||||
expect(wrapper.find('gdd-status-stub').exists()).toBeTruthy()
|
expect(wrapper.find('gdd-status-stub').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
@ -34,30 +30,5 @@ describe('AccountOverview', () => {
|
|||||||
it('has a transactions table', () => {
|
it('has a transactions table', () => {
|
||||||
expect(wrapper.find('gdd-table-stub').exists()).toBeTruthy()
|
expect(wrapper.find('gdd-table-stub').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('updateBalance method', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
wrapper.find('gdd-send-stub').vm.$emit('update-balance', {
|
|
||||||
ammount: 42,
|
|
||||||
})
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('emmits updateBalance with correct value', () => {
|
|
||||||
expect(wrapper.emitted('update-balance')).toEqual([[42]])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('toggleShowList method', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
wrapper.setProps({ showTransactionList: false })
|
|
||||||
wrapper.find('gdd-send-stub').vm.$emit('toggle-show-list', true)
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('changes the value of property showTransactionList', () => {
|
|
||||||
expect(wrapper.vm.showTransactionList).toBeTruthy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,25 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<base-header class="pb-4 pt-2 bg-transparent"></base-header>
|
<b-container fluid class="p-lg-2 mt-lg-1">
|
||||||
<b-container fluid class="p-2 mt-5">
|
<gdd-status
|
||||||
<gdd-status v-if="showTransactionList" :balance="balance" :gdt-balance="GdtBalance" />
|
v-if="showContext"
|
||||||
<br />
|
:pending="pending"
|
||||||
<gdd-send
|
|
||||||
:balance="balance"
|
:balance="balance"
|
||||||
:show-transaction-list="showTransactionList"
|
:gdt-balance="GdtBalance"
|
||||||
@update-balance="updateBalance"
|
|
||||||
@toggle-show-list="toggleShowList"
|
|
||||||
/>
|
/>
|
||||||
|
<br />
|
||||||
|
<gdd-send :currentTransactionStep="currentTransactionStep">
|
||||||
|
<template #transaction-form>
|
||||||
|
<transaction-form :balance="balance" @set-transaction="setTransaction"></transaction-form>
|
||||||
|
</template>
|
||||||
|
<template #transaction-confirmation>
|
||||||
|
<transaction-confirmation
|
||||||
|
:email="transactionData.email"
|
||||||
|
:amount="transactionData.amount"
|
||||||
|
:memo="transactionData.memo"
|
||||||
|
:date="transactionData.target_date"
|
||||||
|
:loading="loading"
|
||||||
|
@send-transaction="sendTransaction"
|
||||||
|
@on-reset="onReset"
|
||||||
|
></transaction-confirmation>
|
||||||
|
</template>
|
||||||
|
<template #transaction-result>
|
||||||
|
<transaction-result :error="error" @on-reset="onReset"></transaction-result>
|
||||||
|
</template>
|
||||||
|
</gdd-send>
|
||||||
<hr />
|
<hr />
|
||||||
<gdd-table
|
<gdd-table
|
||||||
v-if="showTransactionList"
|
v-if="showContext"
|
||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:max="5"
|
:max="5"
|
||||||
:timestamp="timestamp"
|
:timestamp="timestamp"
|
||||||
:transactionCount="transactionCount"
|
:transactionCount="transactionCount"
|
||||||
@update-transactions="updateTransactions"
|
@update-transactions="$emit('update-transactions')"
|
||||||
/>
|
/>
|
||||||
<gdd-table-footer :count="transactionCount" />
|
<gdd-table-footer v-if="showContext" :count="transactionCount" />
|
||||||
</b-container>
|
</b-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -28,6 +45,17 @@ import GddStatus from './AccountOverview/GddStatus.vue'
|
|||||||
import GddSend from './AccountOverview/GddSend.vue'
|
import GddSend from './AccountOverview/GddSend.vue'
|
||||||
import GddTable from './AccountOverview/GddTable.vue'
|
import GddTable from './AccountOverview/GddTable.vue'
|
||||||
import GddTableFooter from './AccountOverview/GddTableFooter.vue'
|
import GddTableFooter from './AccountOverview/GddTableFooter.vue'
|
||||||
|
import TransactionForm from './AccountOverview/GddSend/TransactionForm.vue'
|
||||||
|
import TransactionConfirmation from './AccountOverview/GddSend/TransactionConfirmation.vue'
|
||||||
|
import TransactionResult from './AccountOverview/GddSend/TransactionResult.vue'
|
||||||
|
import communityAPI from '../../apis/communityAPI.js'
|
||||||
|
|
||||||
|
const EMPTY_TRANSACTION_DATA = {
|
||||||
|
email: '',
|
||||||
|
amount: 0,
|
||||||
|
memo: '',
|
||||||
|
target_date: '',
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Overview',
|
name: 'Overview',
|
||||||
@ -36,11 +64,17 @@ export default {
|
|||||||
GddSend,
|
GddSend,
|
||||||
GddTable,
|
GddTable,
|
||||||
GddTableFooter,
|
GddTableFooter,
|
||||||
|
TransactionForm,
|
||||||
|
TransactionConfirmation,
|
||||||
|
TransactionResult,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showTransactionList: true,
|
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
|
transactionData: EMPTY_TRANSACTION_DATA,
|
||||||
|
error: false,
|
||||||
|
currentTransactionStep: 0,
|
||||||
|
loading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -50,16 +84,37 @@ export default {
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
transactionCount: { type: Number, default: 0 },
|
transactionCount: { type: Number, default: 0 },
|
||||||
|
pending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showContext() {
|
||||||
|
return this.currentTransactionStep === 0
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleShowList(bool) {
|
setTransaction(data) {
|
||||||
this.showTransactionList = bool
|
data.target_date = new Date(Date.now()).toISOString()
|
||||||
|
this.transactionData = { ...data }
|
||||||
|
this.currentTransactionStep = 1
|
||||||
},
|
},
|
||||||
updateBalance(data) {
|
async sendTransaction() {
|
||||||
this.$emit('update-balance', data.ammount)
|
this.loading = true
|
||||||
|
const result = await communityAPI.send(this.$store.state.sessionId, this.transactionData)
|
||||||
|
if (result.success) {
|
||||||
|
this.error = false
|
||||||
|
this.$emit('update-balance', this.transactionData.amount)
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
}
|
||||||
|
this.currentTransactionStep = 2
|
||||||
|
this.loading = false
|
||||||
},
|
},
|
||||||
updateTransactions() {
|
onReset() {
|
||||||
this.$emit('update-transactions')
|
this.transactionData = EMPTY_TRANSACTION_DATA
|
||||||
|
this.currentTransactionStep = 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +1,26 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import GddSend from './GddSend'
|
import GddSend from './GddSend'
|
||||||
import Vuex from 'vuex'
|
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
describe('GddSend', () => {
|
describe('GddSend', () => {
|
||||||
let wrapper
|
let wrapper
|
||||||
|
|
||||||
const state = {
|
|
||||||
user: {
|
|
||||||
balance: 1234,
|
|
||||||
balance_gdt: 9876,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
state,
|
|
||||||
})
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
// $n: jest.fn((n) => n),
|
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$moment: jest.fn((m) => ({
|
$store: {
|
||||||
format: () => m,
|
state: {
|
||||||
})),
|
sessionId: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
$i18n: {
|
||||||
|
locale: jest.fn(() => 'en'),
|
||||||
|
},
|
||||||
|
$n: jest.fn((n) => String(n)),
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(GddSend, { localVue, store, mocks })
|
return mount(GddSend, { localVue, mocks })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
@ -38,98 +31,5 @@ describe('GddSend', () => {
|
|||||||
it('renders the component', () => {
|
it('renders the component', () => {
|
||||||
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
|
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('warning messages', () => {
|
|
||||||
it('has a warning message', () => {
|
|
||||||
expect(wrapper.find('div.alert-warning').find('span').text()).toBe('form.attention')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a dismiss button', () => {
|
|
||||||
expect(wrapper.find('div.alert-warning').find('button').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('dismisses the warning when button is clicked', async () => {
|
|
||||||
wrapper.find('div.alert-warning').find('button').trigger('click')
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
expect(wrapper.find('div.alert-warning').exists()).toBeFalsy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('transaction form', () => {
|
|
||||||
describe('email field', () => {
|
|
||||||
it('has an input field of type email', () => {
|
|
||||||
expect(wrapper.find('#input-group-1').find('input').attributes('type')).toBe('email')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has an envelope icon', () => {
|
|
||||||
expect(wrapper.find('#input-group-1').find('svg').attributes('aria-label')).toBe(
|
|
||||||
'envelope',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a label form.receiver', () => {
|
|
||||||
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a placeholder "E-Mail"', () => {
|
|
||||||
expect(wrapper.find('#input-group-1').find('input').attributes('placeholder')).toBe(
|
|
||||||
'E-Mail',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('ammount field', () => {
|
|
||||||
it('has an input field of type number', () => {
|
|
||||||
expect(wrapper.find('#input-group-2').find('input').attributes('type')).toBe('number')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has an GDD text icon', () => {
|
|
||||||
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a label form.amount', () => {
|
|
||||||
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a placeholder "0.01"', () => {
|
|
||||||
expect(wrapper.find('#input-group-2').find('input').attributes('placeholder')).toBe(
|
|
||||||
'0.01',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('message text box', () => {
|
|
||||||
it('has an textarea field', () => {
|
|
||||||
expect(wrapper.find('#input-group-3').find('textarea').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has an chat-right-text icon', () => {
|
|
||||||
expect(wrapper.find('#input-group-3').find('svg').attributes('aria-label')).toBe(
|
|
||||||
'chat right text',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a label form.memo', () => {
|
|
||||||
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('cancel button', () => {
|
|
||||||
it('has a cancel button', () => {
|
|
||||||
expect(wrapper.find('button[type="reset"]').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has the text "form.cancel"', () => {
|
|
||||||
expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset')
|
|
||||||
})
|
|
||||||
|
|
||||||
it.skip('clears the email field on click', async () => {
|
|
||||||
wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv')
|
|
||||||
wrapper.find('button[type="reset"]').trigger('click')
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
expect(wrapper.vm.form.email).toBeNull()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,297 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="gdd-send">
|
<div class="gdd-send">
|
||||||
<b-row v-show="showTransactionList">
|
<slot :name="transactionSteps[currentTransactionStep]" />
|
||||||
<b-col xl="12" md="12">
|
|
||||||
<b-alert show dismissible variant="warning" class="text-center">
|
|
||||||
<span class="alert-text" v-html="$t('form.attention')"></span>
|
|
||||||
</b-alert>
|
|
||||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
|
||||||
<b-alert show variant="secondary">
|
|
||||||
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
|
||||||
<b-col v-show="!scan" lg="12" class="text-right">
|
|
||||||
<a @click="toggle" class="nav-link pointer">
|
|
||||||
<img src="img/icons/gradido/qr-scan-pure.png" height="50" />
|
|
||||||
</a>
|
|
||||||
</b-col>
|
|
||||||
|
|
||||||
<div v-if="scan">
|
|
||||||
<!-- <b-row>
|
|
||||||
<qrcode-capture @detect="onDetect" capture="user" ></qrcode-capture>
|
|
||||||
</b-row> -->
|
|
||||||
|
|
||||||
<qrcode-stream class="mt-3" @decode="onDecode" @detect="onDetect"></qrcode-stream>
|
|
||||||
|
|
||||||
<b-container>
|
|
||||||
<b-row>
|
|
||||||
<b-col lg="8">
|
|
||||||
<b-alert show variant="secondary">
|
|
||||||
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
|
||||||
</b-alert>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</div>
|
|
||||||
<div @click="toggle">
|
|
||||||
<b-alert v-show="scan" show variant="primary" class="pointer text-center">
|
|
||||||
<span class="alert-text">
|
|
||||||
<strong>{{ $t('form.cancel') }}</strong>
|
|
||||||
</span>
|
|
||||||
</b-alert>
|
|
||||||
</div>
|
|
||||||
</b-alert>
|
|
||||||
|
|
||||||
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
|
|
||||||
<b-form
|
|
||||||
role="form"
|
|
||||||
@submit.prevent="handleSubmit(onSubmit)"
|
|
||||||
@reset="onReset"
|
|
||||||
v-if="show"
|
|
||||||
>
|
|
||||||
<br />
|
|
||||||
<div>
|
|
||||||
<qrcode-drop-zone id="input-0" v-model="form.img"></qrcode-drop-zone>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div>
|
|
||||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
|
|
||||||
|
|
||||||
<b-input-group
|
|
||||||
id="input-group-1"
|
|
||||||
label="Empfänger:"
|
|
||||||
label-for="input-1"
|
|
||||||
description="We'll never share your email with anyone else."
|
|
||||||
size="lg"
|
|
||||||
class="mb-3"
|
|
||||||
>
|
|
||||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
|
||||||
<b-icon icon="envelope" class="display-3"></b-icon>
|
|
||||||
</b-input-group-prepend>
|
|
||||||
<b-form-input
|
|
||||||
id="input-1"
|
|
||||||
v-model="form.email"
|
|
||||||
type="email"
|
|
||||||
placeholder="E-Mail"
|
|
||||||
:rules="{ required: true, email: true }"
|
|
||||||
required
|
|
||||||
style="font-size: xx-large; padding-left: 20px"
|
|
||||||
></b-form-input>
|
|
||||||
</b-input-group>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div>
|
|
||||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
|
|
||||||
<b-col v-if="balance == form.amount" class="text-right">
|
|
||||||
<b-badge variant="primary">{{ $t('form.max_gdd_info') }}</b-badge>
|
|
||||||
</b-col>
|
|
||||||
<b-input-group
|
|
||||||
id="input-group-2"
|
|
||||||
label="Betrag:"
|
|
||||||
label-for="input-2"
|
|
||||||
size="lg"
|
|
||||||
class="mb-3"
|
|
||||||
>
|
|
||||||
<b-input-group-prepend class="p-2 d-none d-md-block">
|
|
||||||
<div class="h3 pt-3 pr-3">GDD</div>
|
|
||||||
</b-input-group-prepend>
|
|
||||||
<b-form-input
|
|
||||||
id="input-2"
|
|
||||||
v-model="form.amount"
|
|
||||||
type="number"
|
|
||||||
placeholder="0.01"
|
|
||||||
step="0.01"
|
|
||||||
min="0.01"
|
|
||||||
:max="balance"
|
|
||||||
style="font-size: xx-large; padding-left: 20px"
|
|
||||||
></b-form-input>
|
|
||||||
</b-input-group>
|
|
||||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
|
|
||||||
<b-input-group id="input-group-3">
|
|
||||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
|
||||||
<b-icon icon="chat-right-text" class="display-3"></b-icon>
|
|
||||||
</b-input-group-prepend>
|
|
||||||
<b-form-textarea
|
|
||||||
rows="3"
|
|
||||||
v-model="form.memo"
|
|
||||||
class="pl-3"
|
|
||||||
style="font-size: x-large"
|
|
||||||
></b-form-textarea>
|
|
||||||
</b-input-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<b-button type="reset" variant="secondary" @click="onReset">
|
|
||||||
{{ $t('form.reset') }}
|
|
||||||
</b-button>
|
|
||||||
</b-col>
|
|
||||||
<b-col class="text-right">
|
|
||||||
<b-button type="submit" variant="success">
|
|
||||||
{{ $t('form.send_now') }}
|
|
||||||
</b-button>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
</b-form>
|
|
||||||
</validation-observer>
|
|
||||||
</b-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row v-show="row_check">
|
|
||||||
<b-col>
|
|
||||||
<div class="display-4 p-4">{{ $t('form.send_check') }}</div>
|
|
||||||
|
|
||||||
<b-list-group>
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ ajaxCreateData.email }}
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ ajaxCreateData.amount }} GDD
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.amount') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ ajaxCreateData.memo ? ajaxCreateData.memo : '-' }}
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.message') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ $moment(ajaxCreateData.target_date).format('DD.MM.YYYY - HH:mm:ss') }}
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.date') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
</b-list-group>
|
|
||||||
<hr />
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<b-button @click="onReset">{{ $t('form.cancel') }}</b-button>
|
|
||||||
</b-col>
|
|
||||||
<b-col class="text-right">
|
|
||||||
<b-button variant="success" @click="sendTransaction">
|
|
||||||
{{ $t('form.send_now') }}
|
|
||||||
</b-button>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row v-show="row_thx">
|
|
||||||
<b-col>
|
|
||||||
<div class="display-1 p-4">
|
|
||||||
{{ $t('form.thx') }}
|
|
||||||
<hr />
|
|
||||||
{{ $t('form.send_success') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<b-button variant="success" @click="onReset">{{ $t('form.close') }}</b-button>
|
|
||||||
<hr />
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'
|
|
||||||
import { BIcon } from 'bootstrap-vue'
|
|
||||||
import communityAPI from '../../../apis/communityAPI.js'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'GddSent',
|
name: 'GddSend',
|
||||||
components: {
|
|
||||||
QrcodeStream,
|
|
||||||
QrcodeDropZone,
|
|
||||||
BIcon,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
balance: { type: Number, default: 0 },
|
|
||||||
showTransactionList: { type: Boolean, default: true },
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scan: false,
|
transactionSteps: ['transaction-form', 'transaction-confirmation', 'transaction-result'],
|
||||||
show: true,
|
|
||||||
form: {
|
|
||||||
img: '',
|
|
||||||
email: '',
|
|
||||||
amount: '',
|
|
||||||
memo: '',
|
|
||||||
},
|
|
||||||
ajaxCreateData: {
|
|
||||||
email: '',
|
|
||||||
amount: 0,
|
|
||||||
target_date: '',
|
|
||||||
memo: '',
|
|
||||||
auto_sign: true,
|
|
||||||
},
|
|
||||||
send: false,
|
|
||||||
row_check: false,
|
|
||||||
row_thx: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
props: {
|
||||||
methods: {
|
currentTransactionStep: { type: Number, default: 0 },
|
||||||
toggle() {
|
|
||||||
this.scan = !this.scan
|
|
||||||
},
|
|
||||||
async onDecode(decodedString) {
|
|
||||||
const arr = JSON.parse(decodedString)
|
|
||||||
this.form.email = arr[0].email
|
|
||||||
this.form.amount = arr[0].amount
|
|
||||||
this.scan = false
|
|
||||||
},
|
|
||||||
async onSubmit() {
|
|
||||||
// event.preventDefault()
|
|
||||||
this.ajaxCreateData.email = this.form.email
|
|
||||||
this.ajaxCreateData.amount = this.form.amount
|
|
||||||
const now = new Date(Date.now()).toISOString()
|
|
||||||
this.ajaxCreateData.target_date = now
|
|
||||||
this.ajaxCreateData.memo = this.form.memo
|
|
||||||
this.$emit('toggle-show-list', false)
|
|
||||||
this.row_check = true
|
|
||||||
this.row_thx = false
|
|
||||||
},
|
|
||||||
async sendTransaction() {
|
|
||||||
const result = await communityAPI.send(
|
|
||||||
this.$store.state.sessionId,
|
|
||||||
this.ajaxCreateData.email,
|
|
||||||
this.ajaxCreateData.amount,
|
|
||||||
this.ajaxCreateData.memo,
|
|
||||||
this.ajaxCreateData.target_date,
|
|
||||||
)
|
|
||||||
if (result.success) {
|
|
||||||
this.$emit('toggle-show-list', false)
|
|
||||||
this.row_check = false
|
|
||||||
this.row_thx = true
|
|
||||||
this.$emit('update-balance', { ammount: this.ajaxCreateData.amount })
|
|
||||||
} else {
|
|
||||||
alert('error')
|
|
||||||
this.$emit('toggle-show-list', true)
|
|
||||||
this.row_check = false
|
|
||||||
this.row_thx = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onReset(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.form.email = ''
|
|
||||||
this.form.amount = ''
|
|
||||||
this.form.memo = ''
|
|
||||||
this.show = false
|
|
||||||
this.$emit('toggle-show-list', true)
|
|
||||||
this.row_check = false
|
|
||||||
this.row_thx = false
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.show = true
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.pointer {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
video {
|
|
||||||
max-height: 665px;
|
|
||||||
max-width: 665px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
65
frontend/src/views/Pages/AccountOverview/GddSend/QrCode.vue
Normal file
65
frontend/src/views/Pages/AccountOverview/GddSend/QrCode.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<b-alert show variant="secondary">
|
||||||
|
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
||||||
|
<b-col v-show="!scan" lg="12" class="text-right">
|
||||||
|
<a @click="toggle" class="nav-link pointer">
|
||||||
|
<img src="img/icons/gradido/qr-scan-pure.png" height="50" />
|
||||||
|
</a>
|
||||||
|
</b-col>
|
||||||
|
|
||||||
|
<div v-if="scan">
|
||||||
|
<b-row>
|
||||||
|
<qrcode-capture @detect="onDetect" capture="user"></qrcode-capture>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
<qrcode-stream class="mt-3" @decode="onDecode" @detect="onDetect"></qrcode-stream>
|
||||||
|
|
||||||
|
<b-container>
|
||||||
|
<b-row>
|
||||||
|
<b-col lg="8">
|
||||||
|
<b-alert show variant="secondary">
|
||||||
|
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
||||||
|
</b-alert>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</b-container>
|
||||||
|
</div>
|
||||||
|
<div @click="toggle">
|
||||||
|
<b-alert v-show="scan" show variant="primary" class="pointer text-center">
|
||||||
|
<span class="alert-text">
|
||||||
|
<strong>{{ $t('form.cancel') }}</strong>
|
||||||
|
</span>
|
||||||
|
</b-alert>
|
||||||
|
</div>
|
||||||
|
</b-alert>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { QrcodeStream } from 'vue-qrcode-reader'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'QrCode',
|
||||||
|
components: {
|
||||||
|
QrcodeStream,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
scan: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
this.scan = !this.scan
|
||||||
|
},
|
||||||
|
async onDecode(decodedString) {
|
||||||
|
const arr = JSON.parse(decodedString)
|
||||||
|
this.$emit('set-transaction', { email: arr[0].email, amount: arr[0].amount })
|
||||||
|
this.scan = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<div class="display-4 p-4">{{ $t('form.send_check') }}</div>
|
||||||
|
<b-list-group>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ email }}
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ amount }} GDD
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.amount') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ memo ? memo : '-' }}
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.message') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ date }}
|
||||||
|
{{ $moment(date).format('DD.MM.YYYY - HH:mm:ss') }}
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.date') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
</b-list-group>
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<b-button @click="$emit('on-reset')">{{ $t('form.cancel') }}</b-button>
|
||||||
|
</b-col>
|
||||||
|
<b-col class="text-right">
|
||||||
|
<b-button variant="success" :disabled="loading" @click="$emit('send-transaction')">
|
||||||
|
{{ $t('form.send_now') }}
|
||||||
|
</b-button>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TransactionConfirmation',
|
||||||
|
props: {
|
||||||
|
email: { type: String, default: '' },
|
||||||
|
amount: { type: String, default: '' },
|
||||||
|
memo: { type: String, default: '' },
|
||||||
|
date: { type: String, default: '' },
|
||||||
|
loading: { type: Boolean, default: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import TransactionForm from './TransactionForm'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
describe('GddSend', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$t: jest.fn((t) => t),
|
||||||
|
$moment: jest.fn((m) => ({
|
||||||
|
format: () => m,
|
||||||
|
})),
|
||||||
|
$i18n: {
|
||||||
|
locale: jest.fn(() => 'en'),
|
||||||
|
},
|
||||||
|
$n: jest.fn((n) => String(n)),
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
email: 'user@example.org',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(TransactionForm, { localVue, mocks })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component', () => {
|
||||||
|
expect(wrapper.find('div.transaction-form').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('transaction form', () => {
|
||||||
|
describe('email field', () => {
|
||||||
|
it('has an input field of type email', () => {
|
||||||
|
expect(wrapper.find('#input-group-1').find('input').attributes('type')).toBe('email')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an envelope icon', () => {
|
||||||
|
expect(wrapper.find('#input-group-1').find('svg').attributes('aria-label')).toBe(
|
||||||
|
'envelope',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a label form.receiver', () => {
|
||||||
|
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a placeholder "E-Mail"', () => {
|
||||||
|
expect(wrapper.find('#input-group-1').find('input').attributes('placeholder')).toBe(
|
||||||
|
'E-Mail',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ammount field', () => {
|
||||||
|
it('has an input field of type number', () => {
|
||||||
|
expect(wrapper.find('#input-group-2').find('input').attributes('type')).toBe('number')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an GDD text icon', () => {
|
||||||
|
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a label form.amount', () => {
|
||||||
|
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a placeholder "0.01"', () => {
|
||||||
|
expect(wrapper.find('#input-group-2').find('input').attributes('placeholder')).toBe(
|
||||||
|
'0.01',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('message text box', () => {
|
||||||
|
it('has an textarea field', () => {
|
||||||
|
expect(wrapper.find('#input-group-3').find('textarea').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an chat-right-text icon', () => {
|
||||||
|
expect(wrapper.find('#input-group-3').find('svg').attributes('aria-label')).toBe(
|
||||||
|
'chat right text',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a label form.memo', () => {
|
||||||
|
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('cancel button', () => {
|
||||||
|
it('has a cancel button', () => {
|
||||||
|
expect(wrapper.find('button[type="reset"]').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the text "form.cancel"', () => {
|
||||||
|
expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset')
|
||||||
|
})
|
||||||
|
|
||||||
|
it.skip('clears the email field on click', async () => {
|
||||||
|
wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv')
|
||||||
|
wrapper.find('button[type="reset"]').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.vm.form.email).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<b-row class="transaction-form">
|
||||||
|
<b-col xl="12" md="12">
|
||||||
|
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||||
|
<!-- -<QrCode @set-transaction="setTransaction"></QrCode> -->
|
||||||
|
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
|
||||||
|
<b-form role="form" @submit.prevent="handleSubmit(onSubmit)" @reset="onReset">
|
||||||
|
<!-- <div>
|
||||||
|
<qrcode-drop-zone id="input-0" v-model="form.img"></qrcode-drop-zone>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
-->
|
||||||
|
<div>
|
||||||
|
<validation-provider
|
||||||
|
name="Email"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
email: true,
|
||||||
|
is_not: $store.state.email,
|
||||||
|
}"
|
||||||
|
v-slot="{ errors }"
|
||||||
|
>
|
||||||
|
<b-row>
|
||||||
|
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
|
||||||
|
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||||
|
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-input-group
|
||||||
|
id="input-group-1"
|
||||||
|
label="Empfänger:"
|
||||||
|
label-for="input-1"
|
||||||
|
description="We'll never share your email with anyone else."
|
||||||
|
size="lg"
|
||||||
|
class="mb-3"
|
||||||
|
>
|
||||||
|
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||||
|
<b-icon icon="envelope" class="display-3"></b-icon>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-input
|
||||||
|
id="input-1"
|
||||||
|
v-model="form.email"
|
||||||
|
type="email"
|
||||||
|
placeholder="E-Mail"
|
||||||
|
style="font-size: xx-large; padding-left: 20px"
|
||||||
|
></b-form-input>
|
||||||
|
</b-input-group>
|
||||||
|
</validation-provider>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<validation-provider
|
||||||
|
:name="$t('form.amount')"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
double: [2, $i18n.locale === 'de' ? ',' : '.'],
|
||||||
|
between: [0.01, balance],
|
||||||
|
}"
|
||||||
|
v-slot="{ errors }"
|
||||||
|
>
|
||||||
|
<b-row>
|
||||||
|
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
|
||||||
|
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||||
|
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-input-group
|
||||||
|
id="input-group-2"
|
||||||
|
label="Betrag:"
|
||||||
|
label-for="input-2"
|
||||||
|
size="lg"
|
||||||
|
class="mb-3"
|
||||||
|
>
|
||||||
|
<b-input-group-prepend class="p-2 d-none d-md-block">
|
||||||
|
<div class="h3 pt-3 pr-3">GDD</div>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-input
|
||||||
|
id="input-2"
|
||||||
|
v-model="form.amount"
|
||||||
|
type="number"
|
||||||
|
:lang="$i18n.locale"
|
||||||
|
:placeholder="$n(0.01)"
|
||||||
|
step="0.01"
|
||||||
|
style="font-size: xx-large; padding-left: 20px"
|
||||||
|
></b-form-input>
|
||||||
|
</b-input-group>
|
||||||
|
</validation-provider>
|
||||||
|
<validation-provider
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
min: 5,
|
||||||
|
max: 150,
|
||||||
|
}"
|
||||||
|
:name="$t('form.memo')"
|
||||||
|
v-slot="{ errors }"
|
||||||
|
>
|
||||||
|
<b-row>
|
||||||
|
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
|
||||||
|
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||||
|
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-input-group id="input-group-3">
|
||||||
|
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||||
|
<b-icon icon="chat-right-text" class="display-3"></b-icon>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-textarea
|
||||||
|
rows="3"
|
||||||
|
v-model="form.memo"
|
||||||
|
class="pl-3"
|
||||||
|
style="font-size: x-large"
|
||||||
|
></b-form-textarea>
|
||||||
|
</b-input-group>
|
||||||
|
</validation-provider>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<b-button type="reset" variant="secondary" @click="onReset">
|
||||||
|
{{ $t('form.reset') }}
|
||||||
|
</b-button>
|
||||||
|
</b-col>
|
||||||
|
<b-col class="text-right">
|
||||||
|
<b-button type="submit" variant="success">
|
||||||
|
{{ $t('form.send_now') }}
|
||||||
|
</b-button>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
</b-form>
|
||||||
|
</validation-observer>
|
||||||
|
</b-card>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
// import QrCode from './QrCode'
|
||||||
|
// import { QrcodeDropZone } from 'vue-qrcode-reader'
|
||||||
|
import { BIcon } from 'bootstrap-vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TransactionForm',
|
||||||
|
components: {
|
||||||
|
BIcon,
|
||||||
|
// QrCode,
|
||||||
|
// QrcodeDropZone,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
balance: { type: Number, default: 0 },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
email: '',
|
||||||
|
amount: '',
|
||||||
|
memo: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSubmit() {
|
||||||
|
this.$emit('set-transaction', {
|
||||||
|
email: this.form.email,
|
||||||
|
amount: this.form.amount,
|
||||||
|
memo: this.form.memo,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onReset(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
this.form.email = ''
|
||||||
|
this.form.amount = ''
|
||||||
|
this.form.memo = ''
|
||||||
|
},
|
||||||
|
setTransaction(data) {
|
||||||
|
this.form.email = data.email
|
||||||
|
this.form.amount = data.amount
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
span.errors {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<b-row v-if="!error">
|
||||||
|
<b-col>
|
||||||
|
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||||
|
<div class="display-2 p-4">
|
||||||
|
{{ $t('form.thx') }}
|
||||||
|
<hr />
|
||||||
|
{{ $t('form.send_transaction_success') }}
|
||||||
|
</div>
|
||||||
|
<p class="text-center">
|
||||||
|
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||||
|
</p>
|
||||||
|
</b-card>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-row v-else>
|
||||||
|
<b-col>
|
||||||
|
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||||
|
<div class="display-2 p-4">
|
||||||
|
{{ $t('form.sorry') }}
|
||||||
|
<hr />
|
||||||
|
{{ $t('form.send_transaction_error') }}
|
||||||
|
</div>
|
||||||
|
<p class="text-center">
|
||||||
|
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||||
|
</p>
|
||||||
|
</b-card>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TransactionResult',
|
||||||
|
props: {
|
||||||
|
error: { type: Boolean, default: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -24,12 +24,30 @@ describe('GddStatus', () => {
|
|||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it displays the ammount of GDD', () => {
|
describe('balance is loading', () => {
|
||||||
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD')
|
it('it displays em-dash as the ammount of GDD', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('— GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it displays em-dash as the ammount of GDT', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('— GDT')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it displays the ammount of GDT', () => {
|
describe('balance is loaded', () => {
|
||||||
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT')
|
beforeEach(() => {
|
||||||
|
wrapper.setProps({
|
||||||
|
pending: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it displays the ammount of GDD', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it displays the ammount of GDT', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,24 +2,14 @@
|
|||||||
<div>
|
<div>
|
||||||
<b-row>
|
<b-row>
|
||||||
<b-col>
|
<b-col>
|
||||||
<stats-card
|
<b-card style="background-color: #ebebeba3 !important">
|
||||||
type="gradient-red"
|
{{ pending ? '—' : $n(balance) }} GDD
|
||||||
sub-title="balance_gdd"
|
</b-card>
|
||||||
class="mb-4 h1"
|
|
||||||
style="background-color: #ebebeba3 !important"
|
|
||||||
>
|
|
||||||
{{ $n(balance) }} GDD
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col>
|
<b-col>
|
||||||
<stats-card
|
<b-card class="lg-h2 text-right" style="background-color: #ebebeba3 !important">
|
||||||
type="gradient-orange"
|
{{ pending ? '—' : $n(GdtBalance) }} GDT
|
||||||
sub-title="balance_gdt"
|
</b-card>
|
||||||
class="mb-4 h1"
|
|
||||||
style="background-color: #ebebeba3 !important"
|
|
||||||
>
|
|
||||||
{{ $n(GdtBalance) }} GDT
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
</div>
|
</div>
|
||||||
@ -31,6 +21,10 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
balance: { type: Number, default: 0 },
|
balance: { type: Number, default: 0 },
|
||||||
GdtBalance: { type: Number, default: 0 },
|
GdtBalance: { type: Number, default: 0 },
|
||||||
|
pending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -88,11 +88,9 @@
|
|||||||
</b-card>
|
</b-card>
|
||||||
</b-collapse>
|
</b-collapse>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
<b-list-group-item>
|
<div v-if="transactions.length === 0" class="mt-lg-4 text-center">
|
||||||
<b-alert v-if="transactions.length === 0" show variant="secondary">
|
<span>{{ $t('transaction.nullTransactions') }}</span>
|
||||||
<span class="alert-text">{{ $t('transaction.nullTransactions') }}</span>
|
</div>
|
||||||
</b-alert>
|
|
||||||
</b-list-group-item>
|
|
||||||
</b-list-group>
|
</b-list-group>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -102,7 +100,7 @@ export default {
|
|||||||
name: 'GddTable',
|
name: 'GddTable',
|
||||||
props: {
|
props: {
|
||||||
transactions: { default: [] },
|
transactions: { default: [] },
|
||||||
max: { type: Number, default: 25 },
|
max: { type: Number, default: 1000 },
|
||||||
timestamp: { type: Number, default: 0 },
|
timestamp: { type: Number, default: 0 },
|
||||||
transactionCount: { type: Number, default: 0 },
|
transactionCount: { type: Number, default: 0 },
|
||||||
},
|
},
|
||||||
|
|||||||
@ -62,7 +62,7 @@ export default {
|
|||||||
async onSubmit() {
|
async onSubmit() {
|
||||||
const result = await loginAPI.sendEmail(this.form.email)
|
const result = await loginAPI.sendEmail(this.form.email)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.$router.push({ path: '/thx', params: { id: 'resetmail' } })
|
this.$router.push('/thx/password')
|
||||||
} else {
|
} else {
|
||||||
alert(result.result)
|
alert(result.result)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||||
import Vuex from 'vuex'
|
|
||||||
import flushPromises from 'flush-promises'
|
import flushPromises from 'flush-promises'
|
||||||
|
|
||||||
import Login from './Login'
|
import Login from './Login'
|
||||||
@ -16,20 +15,12 @@ describe('Login', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = {
|
|
||||||
loginfail: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
state,
|
|
||||||
})
|
|
||||||
|
|
||||||
const stubs = {
|
const stubs = {
|
||||||
RouterLink: RouterLinkStub,
|
RouterLink: RouterLinkStub,
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(Login, { localVue, mocks, store, stubs })
|
return mount(Login, { localVue, mocks, stubs })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
|
|||||||
@ -34,15 +34,22 @@
|
|||||||
v-model="model.email"
|
v-model="model.email"
|
||||||
></base-input>
|
></base-input>
|
||||||
|
|
||||||
<base-input
|
<b-input-group>
|
||||||
alternative
|
<b-form-input
|
||||||
class="mb-3"
|
class="mb-0"
|
||||||
name="Password"
|
v-model="model.password"
|
||||||
prepend-icon="ni ni-lock-circle-open"
|
name="Password"
|
||||||
type="password"
|
:type="passwordVisible ? 'text' : 'password'"
|
||||||
:placeholder="$t('form.password')"
|
prepend-icon="ni ni-lock-circle-open"
|
||||||
v-model="model.password"
|
:placeholder="$t('form.password')"
|
||||||
></base-input>
|
></b-form-input>
|
||||||
|
|
||||||
|
<b-input-group-append>
|
||||||
|
<b-button variant="outline-primary" @click="togglePasswordVisibility">
|
||||||
|
<b-icon :icon="passwordVisible ? 'eye' : 'eye-slash'" />
|
||||||
|
</b-button>
|
||||||
|
</b-input-group-append>
|
||||||
|
</b-input-group>
|
||||||
|
|
||||||
<b-alert v-show="loginfail" show dismissible variant="warning">
|
<b-alert v-show="loginfail" show dismissible variant="warning">
|
||||||
<span class="alert-text bv-example-row">
|
<span class="alert-text bv-example-row">
|
||||||
@ -98,9 +105,13 @@ export default {
|
|||||||
},
|
},
|
||||||
loginfail: false,
|
loginfail: false,
|
||||||
allowRegister: CONFIG.ALLOW_REGISTER,
|
allowRegister: CONFIG.ALLOW_REGISTER,
|
||||||
|
passwordVisible: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
togglePasswordVisibility() {
|
||||||
|
this.passwordVisible = !this.passwordVisible
|
||||||
|
},
|
||||||
async onSubmit() {
|
async onSubmit() {
|
||||||
// error info ausschalten
|
// error info ausschalten
|
||||||
this.loginfail = false
|
this.loginfail = false
|
||||||
@ -111,7 +122,7 @@ export default {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.$store.dispatch('login', {
|
this.$store.dispatch('login', {
|
||||||
sessionId: result.result.data.session_id,
|
sessionId: result.result.data.session_id,
|
||||||
email: this.model.email,
|
user: result.result.data.user,
|
||||||
})
|
})
|
||||||
this.$router.push('/overview')
|
this.$router.push('/overview')
|
||||||
loader.hide()
|
loader.hide()
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||||
import Vuex from 'vuex'
|
|
||||||
import flushPromises from 'flush-promises'
|
import flushPromises from 'flush-promises'
|
||||||
|
|
||||||
import Register from './Register'
|
import Register from './Register'
|
||||||
@ -16,20 +15,12 @@ describe('Register', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = {
|
|
||||||
// loginfail: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
state,
|
|
||||||
})
|
|
||||||
|
|
||||||
const stubs = {
|
const stubs = {
|
||||||
RouterLink: RouterLinkStub,
|
RouterLink: RouterLinkStub,
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(Register, { localVue, mocks, store, stubs })
|
return mount(Register, { localVue, mocks, stubs })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
|
|||||||
@ -97,7 +97,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<b-row class="my-4">
|
<b-row class="my-4">
|
||||||
<b-col cols="12">
|
<b-col cols="12">
|
||||||
<base-input
|
<base-input
|
||||||
@ -164,12 +163,7 @@ export default {
|
|||||||
email: '',
|
email: '',
|
||||||
agree: false,
|
agree: false,
|
||||||
},
|
},
|
||||||
rules: [
|
|
||||||
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
|
||||||
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
|
||||||
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
|
||||||
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
|
||||||
],
|
|
||||||
password: '',
|
password: '',
|
||||||
checkPassword: '',
|
checkPassword: '',
|
||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
@ -198,7 +192,7 @@ export default {
|
|||||||
this.model.firstname = ''
|
this.model.firstname = ''
|
||||||
this.model.lastname = ''
|
this.model.lastname = ''
|
||||||
this.password = ''
|
this.password = ''
|
||||||
this.$router.push('/thx')
|
this.$router.push('/thx/register')
|
||||||
} else {
|
} else {
|
||||||
this.showError = true
|
this.showError = true
|
||||||
this.messageError = result.result.message
|
this.messageError = result.result.message
|
||||||
@ -231,6 +225,14 @@ export default {
|
|||||||
emailFilled() {
|
emailFilled() {
|
||||||
return this.model.email !== ''
|
return this.model.email !== ''
|
||||||
},
|
},
|
||||||
|
rules() {
|
||||||
|
return [
|
||||||
|
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
||||||
|
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
||||||
|
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
||||||
|
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
||||||
|
]
|
||||||
|
},
|
||||||
passwordValidation() {
|
passwordValidation() {
|
||||||
const errors = []
|
const errors = []
|
||||||
for (const condition of this.rules) {
|
for (const condition of this.rules) {
|
||||||
|
|||||||
@ -90,12 +90,6 @@ export default {
|
|||||||
name: 'reset',
|
name: 'reset',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
rules: [
|
|
||||||
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
|
||||||
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
|
||||||
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
|
||||||
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
|
||||||
],
|
|
||||||
password: '',
|
password: '',
|
||||||
checkPassword: '',
|
checkPassword: '',
|
||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
@ -113,7 +107,13 @@ export default {
|
|||||||
const result = await loginAPI.changePassword(this.sessionId, this.email, this.password)
|
const result = await loginAPI.changePassword(this.sessionId, this.email, this.password)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.password = ''
|
this.password = ''
|
||||||
this.$router.push('/thx')
|
/*
|
||||||
|
this.$store.dispatch('login', {
|
||||||
|
sessionId: result.result.data.session_id,
|
||||||
|
email: result.result.data.user.email,
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
this.$router.push('/thx/reset')
|
||||||
} else {
|
} else {
|
||||||
alert(result.result.message)
|
alert(result.result.message)
|
||||||
}
|
}
|
||||||
@ -137,6 +137,14 @@ export default {
|
|||||||
passwordsFilled() {
|
passwordsFilled() {
|
||||||
return this.password !== '' && this.checkPassword !== ''
|
return this.password !== '' && this.checkPassword !== ''
|
||||||
},
|
},
|
||||||
|
rules() {
|
||||||
|
return [
|
||||||
|
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
||||||
|
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
||||||
|
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
||||||
|
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
||||||
|
]
|
||||||
|
},
|
||||||
passwordValidation() {
|
passwordValidation() {
|
||||||
const errors = []
|
const errors = []
|
||||||
for (const condition of this.rules) {
|
for (const condition of this.rules) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="header pb-8 pt-5 pt-lg-8 d-flex align-items-center profile-header"
|
class="header pb-8 pt-lg-4 d-flex align-items-center profile-header"
|
||||||
style="max-height: 200px"
|
style="max-height: 200px"
|
||||||
></div>
|
></div>
|
||||||
<b-container fluid class="mt--6">
|
<b-container fluid class="mt--6">
|
||||||
|
|||||||
@ -1,28 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header bg-gradient-info py-7 py-lg-8 pt-lg-9">
|
<div class="header py-7 py-lg-8 pt-lg-9">
|
||||||
<b-container>
|
<b-container>
|
||||||
<div class="header-body text-center mb-7">
|
<div class="header-body text-center mb-7">
|
||||||
<p class="h1">{{ $t('site.thx.title') }}</p>
|
<p class="h1">{{ $t('site.thx.title') }}</p>
|
||||||
<p class="h4">{{ $t('site.thx.subtitle') }}</p>
|
<p class="h4">{{ $t(displaySetup.subtitle) }}</p>
|
||||||
<hr />
|
<hr />
|
||||||
<b-button to="/login">{{ $t('login') }}</b-button>
|
<b-button :to="displaySetup.linkTo">{{ $t(displaySetup.button) }}</b-button>
|
||||||
</div>
|
</div>
|
||||||
</b-container>
|
</b-container>
|
||||||
<div class="separator separator-bottom separator-skew zindex-100">
|
|
||||||
<svg
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
viewBox="0 0 2560 100"
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<polygon class="fill-default" points="2560 0 2560 100 0 100"></polygon>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Page content -->
|
<!-- Page content -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<script>
|
||||||
|
const textFields = {
|
||||||
|
password: {
|
||||||
|
subtitle: 'site.thx.email',
|
||||||
|
button: 'login',
|
||||||
|
linkTo: '/login',
|
||||||
|
},
|
||||||
|
reset: {
|
||||||
|
subtitle: 'site.thx.reset',
|
||||||
|
button: 'login',
|
||||||
|
linkTo: '/login',
|
||||||
|
},
|
||||||
|
register: {
|
||||||
|
subtitle: 'site.thx.register',
|
||||||
|
button: 'site.login.signin',
|
||||||
|
linkTo: '/overview',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Thx',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
displaySetup: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setDisplaySetup(from) {
|
||||||
|
this.displaySetup = textFields[this.$route.params.comingFrom]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.setDisplaySetup()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@ -2,10 +2,17 @@ cmake_minimum_required(VERSION 3.18.2)
|
|||||||
project(Gradido_LoginServer C CXX)
|
project(Gradido_LoginServer C CXX)
|
||||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin" )
|
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin" )
|
||||||
|
|
||||||
SET ( CMAKE_CXX_FLAGS "-std=c++17" )
|
SET(CMAKE_CXX_FLAGS "-std=c++17" )
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
IF(WIN32)
|
||||||
|
set(CMAKE_CXX_FLAGS "/MP /EHsc")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
set(INSTALL_BINDIR "bin")
|
||||||
|
set(INSTALL_PLUGINDIR "bin")
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
"dependencies"
|
"dependencies"
|
||||||
"dependencies/tinf/src/"
|
"dependencies/tinf/src/"
|
||||||
@ -14,13 +21,119 @@ include_directories(
|
|||||||
"dependencies/spirit-po/include"
|
"dependencies/spirit-po/include"
|
||||||
"dependencies/grpc/include"
|
"dependencies/grpc/include"
|
||||||
"dependencies/grpc/third_party/protobuf/src"
|
"dependencies/grpc/third_party/protobuf/src"
|
||||||
"src/cpp/proto"
|
"dependencies/grpc/third_party/googletest/googletest/include"
|
||||||
|
"build"
|
||||||
|
"build/proto"
|
||||||
)
|
)
|
||||||
#if(WIN32)
|
|
||||||
#include_directories("dependencies/mariadb-connector-c/include", "dependencies/mariadb-connector-c/build/include")
|
|
||||||
set(MYSQL_INCLUDE_DIR "dependencies/mariadb-connector-c/include")
|
|
||||||
|
|
||||||
#endif(WIN32)
|
IF(UNIX)
|
||||||
|
include_directories(
|
||||||
|
"dependencies/poco/Crypto/include"
|
||||||
|
"dependencies/poco/Data/include"
|
||||||
|
"dependencies/poco/Util/include"
|
||||||
|
"dependencies/poco/Foundation/include"
|
||||||
|
"dependencies/poco/JSON/include"
|
||||||
|
"dependencies/poco/Net/include"
|
||||||
|
"dependencies/poco/NetSSL_OpenSSL/include"
|
||||||
|
)
|
||||||
|
ENDIF()
|
||||||
|
############################## config and add grpc ###################################
|
||||||
|
|
||||||
|
set(GRPC_PATH "${DEP_PATH}/grpc/build")
|
||||||
|
set(GRPC_ABSL_PATH "${GRPC_PATH}/third_party/abseil-cpp/absl/types")
|
||||||
|
set(GRPC_CARES_PATH "${GRPC_PATH}/third_party/cares/cares/lib")
|
||||||
|
set(GRPC_BORING_SSL_PATH "${GRPC_PATH}/third_party/boringssl-with-bazel")
|
||||||
|
set(GRPC_RE2_PATH "${GRPC_PATH}/third_party/re2")
|
||||||
|
set(GRPC_PROTOBUF_PATH "${GRPC_PATH}/third_party/protobuf")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(GRPC_PATH "${GRPC_PATH}/Debug")
|
||||||
|
set(GRPC_ABSL_PATH "${GRPC_ABSL_PATH}/Debug")
|
||||||
|
set(GRPC_CARES_PATH "${GRPC_CARES_PATH}/Debug")
|
||||||
|
set(GRPC_BORING_SSL_PATH "${GRPC_CGRPC_BORING_SSL_PATHARES_PATH}/Debug")
|
||||||
|
set(GRPC_RE2_PATH "${GRPC_RE2_PATH}/Debug")
|
||||||
|
set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}/Debug")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set(BUILD_TESTING OFF)
|
||||||
|
#set(gRPC_SSL_PROVIDER "package")
|
||||||
|
add_subdirectory("dependencies/grpc/")
|
||||||
|
#set(gRPC_SSL_PROVIDER "package")
|
||||||
|
message(STATUS "Using gRPC via add_subdirectory.")
|
||||||
|
|
||||||
|
set(GRPC_LIBS libprotobuf grpc++_reflection grpc++)
|
||||||
|
|
||||||
|
############################## parse protobuf files ###################################
|
||||||
|
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto GRADIDO_PROTO_MODEL_PATH)
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto/hedera/hedera-protobuf/src/main/proto HEDERA_PROTO_MODEL_PATH)
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/proto PROTOBINDING_PATH)
|
||||||
|
file(MAKE_DIRECTORY ${PROTOBINDING_PATH})
|
||||||
|
file(MAKE_DIRECTORY ${PROTOBINDING_PATH}/gradido)
|
||||||
|
file(MAKE_DIRECTORY ${PROTOBINDING_PATH}/hedera)
|
||||||
|
|
||||||
|
FILE(GLOB DATAMODEL_GRADIDO_PROTOS "${GRADIDO_PROTO_MODEL_PATH}/gradido/*.proto")
|
||||||
|
FILE(GLOB DATAMODEL_HEDERA_PROTOS "${HEDERA_PROTO_MODEL_PATH}/*.proto")
|
||||||
|
|
||||||
|
IF(WIN32)
|
||||||
|
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin PATHS "build/dependencies/grpc/bin/Debug")
|
||||||
|
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin PATHS "build/dependencies/grpc/bin/Release")
|
||||||
|
find_program(PROTOBUF_PROTOC_EXECUTABLE protoc PATHS "build/dependencies/grpc/third_party/protobuf/bin/Debug" )
|
||||||
|
find_program(PROTOBUF_PROTOC_EXECUTABLE protoc PATHS "build/dependencies/grpc/third_party/protobuf/bin/Release" )
|
||||||
|
ELSE()
|
||||||
|
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin PATHS "build/dependencies/grpc/bin")
|
||||||
|
find_program(PROTOBUF_PROTOC_EXECUTABLE protoc PATHS "build/dependencies/grpc/third_party/protobuf/bin" )
|
||||||
|
ENDIF()
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/grpc/third_party/protobuf/src GOOGLE_PROTOBUF_INCLUDES)
|
||||||
|
MESSAGE("protoc: ${PROTOBUF_PROTOC_EXECUTABLE} in build/dependencies/grpc/bin/${CMAKE_BUILD_TYPE}")
|
||||||
|
FOREACH(proto ${DATAMODEL_GRADIDO_PROTOS})
|
||||||
|
FILE(TO_NATIVE_PATH ${proto} proto_native)
|
||||||
|
get_filename_component(proto_parsed ${proto} NAME_WLE)
|
||||||
|
FILE(TO_NATIVE_PATH ${PROTOBINDING_PATH}/gradido/${proto_parsed}.pb.h proto_parsed_native)
|
||||||
|
|
||||||
|
IF(${proto_native} IS_NEWER_THAN ${proto_parsed_native})
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND
|
||||||
|
${PROTOBUF_PROTOC_EXECUTABLE}
|
||||||
|
--proto_path=${GRADIDO_PROTO_MODEL_PATH}
|
||||||
|
--cpp_out=${PROTOBINDING_PATH}
|
||||||
|
${proto_native}
|
||||||
|
RESULT_VARIABLE rv
|
||||||
|
)
|
||||||
|
# Optional, but that can show the user if something have gone wrong with the proto generation
|
||||||
|
IF(${rv})
|
||||||
|
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ENDFOREACH(proto)
|
||||||
|
|
||||||
|
FOREACH(proto ${DATAMODEL_HEDERA_PROTOS})
|
||||||
|
FILE(TO_NATIVE_PATH ${proto} proto_native)
|
||||||
|
get_filename_component(proto_parsed ${proto} NAME_WLE)
|
||||||
|
FILE(TO_NATIVE_PATH ${PROTOBINDING_PATH}/hedera/${proto_parsed}.pb.h proto_parsed_native)
|
||||||
|
IF(${proto_native} IS_NEWER_THAN ${proto_parsed_native})
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND
|
||||||
|
${PROTOBUF_PROTOC_EXECUTABLE}
|
||||||
|
--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||||
|
--proto_path=${HEDERA_PROTO_MODEL_PATH}
|
||||||
|
--proto_path=${GOOGLE_PROTOBUF_INCLUDES}
|
||||||
|
--cpp_out=${PROTOBINDING_PATH}/hedera
|
||||||
|
--grpc_out ${PROTOBINDING_PATH}/hedera
|
||||||
|
${proto_native}
|
||||||
|
RESULT_VARIABLE rv
|
||||||
|
)
|
||||||
|
# Optional, but that can show the user if something have gone wrong with the proto generation
|
||||||
|
IF(${rv})
|
||||||
|
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDFOREACH(proto)
|
||||||
|
|
||||||
|
|
||||||
|
############################## bind source files ###################################
|
||||||
|
|
||||||
FILE(GLOB CONTROLLER "src/cpp/controller/*.cpp" "src/cpp/controller/*.h")
|
FILE(GLOB CONTROLLER "src/cpp/controller/*.cpp" "src/cpp/controller/*.h")
|
||||||
FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h")
|
FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h")
|
||||||
@ -37,8 +150,8 @@ FILE(GLOB MODEL_GRADIDO "src/cpp/model/gradido/*.h" "src/cpp/model/gradido/*.cpp
|
|||||||
FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp")
|
FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp")
|
||||||
FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h")
|
FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h")
|
||||||
FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h")
|
FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h")
|
||||||
FILE(GLOB PROTO_GRADIDO "src/cpp/proto/gradido/*.cc" "src/cpp/proto/gradido/*.h")
|
FILE(GLOB PROTO_GRADIDO "build/proto/gradido/*.cc" "build/proto/gradido/*.h")
|
||||||
FILE(GLOB PROTO_HEDERA "src/cpp/proto/hedera/*.cc" "src/cpp/proto/hedera/*.h")
|
FILE(GLOB PROTO_HEDERA "build/proto/hedera/*.cc" "build/proto/hedera/*.h")
|
||||||
|
|
||||||
# used only for test project
|
# used only for test project
|
||||||
FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h")
|
FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h")
|
||||||
@ -84,12 +197,15 @@ if(MSVC)
|
|||||||
source_group("Test" FILES ${TEST})
|
source_group("Test" FILES ${TEST})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
IF(WIN32)
|
||||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||||
conan_basic_setup()
|
conan_basic_setup()
|
||||||
|
#add_compile_definitions(POCO_NETSSL_WIN)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
add_executable(Gradido_LoginServer ${LOCAL_SRCS})
|
add_executable(Gradido_LoginServer ${LOCAL_SRCS})
|
||||||
|
|
||||||
|
############################## config and add mariadb ###################################
|
||||||
set(CLIENT_PLUGIN_DIALOG OFF)
|
set(CLIENT_PLUGIN_DIALOG OFF)
|
||||||
set(CLIENT_PLUGIN_MYSQL_CLEAR_PASSWORD OFF)
|
set(CLIENT_PLUGIN_MYSQL_CLEAR_PASSWORD OFF)
|
||||||
set(CLIENT_PLUGIN_REMOTE_IO OFF)
|
set(CLIENT_PLUGIN_REMOTE_IO OFF)
|
||||||
@ -111,99 +227,34 @@ add_subdirectory("dependencies/mariadb-connector-c")
|
|||||||
set(DEP_PATH "dependencies")
|
set(DEP_PATH "dependencies")
|
||||||
set(MARIADB_CONNECTOR_PATH "${DEP_PATH}/mariadb-connector-c/build/libmariadb")
|
set(MARIADB_CONNECTOR_PATH "${DEP_PATH}/mariadb-connector-c/build/libmariadb")
|
||||||
|
|
||||||
set(GRPC_PATH "${DEP_PATH}/grpc/build")
|
#if(WIN32)
|
||||||
set(GRPC_ABSL_PATH "${GRPC_PATH}/third_party/abseil-cpp/absl/types")
|
#find_library(MYSQL_LIBRARIES mariadbclient PATHS "${MARIADB_CONNECTOR_PATH}/Release" REQUIRED)
|
||||||
set(GRPC_CARES_PATH "${GRPC_PATH}/third_party/cares/cares/lib")
|
#find_library(COMPILED_MARIADB_CLIENT_DEBUG mariadbclient PATHS "${MARIADB_CONNECTOR_PATH}/Debug" REQUIRED)
|
||||||
set(GRPC_BORING_SSL_PATH "${GRPC_PATH}/third_party/boringssl-with-bazel")
|
#endif()
|
||||||
set(GRPC_RE2_PATH "${GRPC_PATH}/third_party/re2")
|
|
||||||
set(GRPC_PROTOBUF_PATH "${GRPC_PATH}/third_party/protobuf")
|
############################## config and add poco ###################################
|
||||||
|
#SET(SOME_EXPAT_OPTION OFF CACHE BOOL "Use some expat option")
|
||||||
|
IF(UNIX)
|
||||||
|
SET(ENABLE_MONGODB OFF CACHE BOOL "" FORCE)
|
||||||
|
SET(ENABLE_DATA_SQLITE OFF CACHE BOOL "" FORCE)
|
||||||
|
SET(ENABLE_REDIS OFF CACHE BOOL "" FORCE)
|
||||||
|
SET(ENABLE_PAGECOMPILER_FILE2PAGE OFF CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory("dependencies/poco")
|
||||||
|
|
||||||
|
set(POCO_LIBS PocoFoundation PocoUtil PocoNet PocoNetSSL PocoData)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
|
############################## build login server ###################################
|
||||||
|
|
||||||
|
target_link_libraries(Gradido_LoginServer ${GRPC_LIBS})
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
target_link_libraries(Gradido_LoginServer mariadbclient ${CONAN_LIBS})
|
||||||
find_library(MYSQL_LIBRARIES mariadbclient PATHS "${MARIADB_CONNECTOR_PATH}/Release" REQUIRED)
|
#TARGET_LINK_LIBRARIES(Gradido_LoginServer optimized ${MYSQL_LIBRARIES} Shlwapi)
|
||||||
find_library(COMPILED_MARIADB_CLIENT_DEBUG mariadbclient PATHS "${MARIADB_CONNECTOR_PATH}/Debug" REQUIRED)
|
#TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
|
||||||
|
|
||||||
find_library(CONAN_OPENSSL_SSL ssleay32 PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH )
|
|
||||||
find_library(CONAN_OPENSSL_CRYPTO libeay32 PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH )
|
|
||||||
|
|
||||||
set(GRPC_PATH "${GRPC_PATH}/Debug")
|
|
||||||
set(GRPC_ABSL_PATH "${GRPC_ABSL_PATH}/Debug")
|
|
||||||
set(GRPC_CARES_PATH "${GRPC_CARES_PATH}/Debug")
|
|
||||||
set(GRPC_BORING_SSL_PATH "${GRPC_CGRPC_BORING_SSL_PATHARES_PATH}/Debug")
|
|
||||||
set(GRPC_RE2_PATH "${GRPC_RE2_PATH}/Debug")
|
|
||||||
set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}/Debug")
|
|
||||||
|
|
||||||
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "libeay32.lib")
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "ssleay32.lib")
|
|
||||||
|
|
||||||
|
|
||||||
else()
|
|
||||||
#find_package(MariaDBClient PATHS "dependencies/cmake-modules")
|
|
||||||
#find_library(MYSQL_LIBRARIES libmariadb.so PATHS ${MARIADB_CONNECTOR_PATH} REQUIRED)
|
|
||||||
find_library(CONAN_OPENSSL_SSL ssl PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH )
|
|
||||||
find_library(CONAN_OPENSSL_CRYPTO crypto PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH )
|
|
||||||
set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}")
|
|
||||||
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "ssl")
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "crypto")
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "dl")
|
|
||||||
|
|
||||||
# find_library(MYSQL_LIBRARIES libmariadb.so PATHS ${MARIADB_CONNECTOR_PATH} REQUIRED)
|
|
||||||
find_library(CONAN_OPENSSL_SSL ssl PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH )
|
|
||||||
find_library(CONAN_OPENSSL_CRYPTO crypto PATHS ${CONAN_LIB_DIRS_OPENSSL} REQUIRED NO_DEFAULT_PATH )
|
|
||||||
set(GRPC_PROTOBUF_DEBUG_PATH "${GRPC_PROTOBUF_PATH}")
|
|
||||||
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "ssl")
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "crypto")
|
|
||||||
list(REMOVE_ITEM CONAN_LIBS "dl")
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# load same ssl version like used from poco
|
|
||||||
#find_package(OpenSSL PATHS "../" NO_DEFAULT_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
set(CONAN_OPENSSL_CUSTOM_LIBS
|
|
||||||
${CONAN_OPENSSL_SSL}
|
|
||||||
${CONAN_OPENSSL_CRYPTO}
|
|
||||||
)
|
|
||||||
include_directories(${CONAN_INCLUDE_DIRS_OPENSSL})
|
|
||||||
# build grpc
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "/MP /EHsc")
|
|
||||||
#set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
|
|
||||||
#set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
|
||||||
|
|
||||||
else()
|
|
||||||
|
|
||||||
set(INSTALL_BINDIR "bin")
|
|
||||||
set(INSTALL_PLUGINDIR "bin")
|
|
||||||
target_link_libraries(Gradido_LoginServer ${CONAN_OPENSSL_CUSTOM_LIBS})
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(BUILD_TESTING OFF)
|
|
||||||
set(gRPC_SSL_PROVIDER "package")
|
|
||||||
add_subdirectory("dependencies/grpc/")
|
|
||||||
set(gRPC_SSL_PROVIDER "package")
|
|
||||||
message(STATUS "Using gRPC via add_subdirectory.")
|
|
||||||
|
|
||||||
set(GRPC_LIBS libprotobuf grpc++_reflection grpc++)
|
|
||||||
target_link_libraries(Gradido_LoginServer ${CONAN_LIBS})
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer optimized ${MYSQL_LIBRARIES} Shlwapi)
|
|
||||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
|
|
||||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS})
|
|
||||||
else() # unix
|
else() # unix
|
||||||
target_link_libraries(Gradido_LoginServer libmariadb ${GRPC_LIBS} ${CMAKE_DL_LIBS} ${PROTOBUF_LIBS})
|
target_link_libraries(Gradido_LoginServer ${POCO_LIBS} libmariadb sodium)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# install
|
# install
|
||||||
@ -228,15 +279,15 @@ enable_testing()
|
|||||||
add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC})
|
add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC})
|
||||||
target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
|
target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
|
||||||
|
|
||||||
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} )
|
target_link_libraries(Gradido_LoginServer_Test ${GRPC_LIBS} )
|
||||||
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi)
|
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} )
|
||||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
|
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi)
|
||||||
TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS})
|
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
|
||||||
|
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS})
|
||||||
else()
|
else()
|
||||||
target_link_libraries(Gradido_LoginServer_Test libmariadb ${GRPC_LIBS} ${CMAKE_DL_LIBS} ${PROTOBUF_LIBS})
|
target_link_libraries(Gradido_LoginServer_Test ${POCO_LIBS} libmariadb sodium)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_test(NAME main COMMAND Gradido_LoginServer_Test)
|
add_test(NAME main COMMAND Gradido_LoginServer_Test)
|
||||||
|
|||||||
189
login_server/CMakeLists.txt.lib
Normal file
189
login_server/CMakeLists.txt.lib
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.18.2)
|
||||||
|
project(Gradido_LoginServer C CXX)
|
||||||
|
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin" )
|
||||||
|
|
||||||
|
SET ( CMAKE_CXX_FLAGS "-std=c++17" )
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(CMAKE_CXX_FLAGS "/MP /EHsc")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||||
|
else()
|
||||||
|
set(INSTALL_BINDIR "bin")
|
||||||
|
set(INSTALL_PLUGINDIR "bin")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
"dependencies"
|
||||||
|
"dependencies/tinf/src"
|
||||||
|
"dependencies/spirit-po/include"
|
||||||
|
"/usr/local/include/mariadb"
|
||||||
|
"build"
|
||||||
|
"build/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
############################## config and add grpc ###################################
|
||||||
|
find_package(Protobuf REQUIRED)
|
||||||
|
include_directories(${Protobuf_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
FIND_PACKAGE(gRPC CONFIG REQUIRED)
|
||||||
|
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
|
||||||
|
|
||||||
|
set(PROTOBUF_LIBS protobuf::libprotobuf protobuf::libprotobuf-lite protobuf::libprotoc)
|
||||||
|
|
||||||
|
############################## parse proto files ###################################
|
||||||
|
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto GRADIDO_PROTO_MODEL_PATH)
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto/hedera/hedera-protobuf/src/main/proto HEDERA_PROTO_MODEL_PATH)
|
||||||
|
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/proto PROTOBINDING_PATH)
|
||||||
|
file(MAKE_DIRECTORY ${PROTOBINDING_PATH})
|
||||||
|
file(MAKE_DIRECTORY ${PROTOBINDING_PATH}/gradido)
|
||||||
|
file(MAKE_DIRECTORY ${PROTOBINDING_PATH}/hedera)
|
||||||
|
|
||||||
|
FILE(GLOB DATAMODEL_GRADIDO_PROTOS "${GRADIDO_PROTO_MODEL_PATH}/gradido/*.proto")
|
||||||
|
FILE(GLOB DATAMODEL_HEDERA_PROTOS "${HEDERA_PROTO_MODEL_PATH}/*.proto")
|
||||||
|
|
||||||
|
FOREACH(proto ${DATAMODEL_GRADIDO_PROTOS})
|
||||||
|
FILE(TO_NATIVE_PATH ${proto} proto_native)
|
||||||
|
get_filename_component(proto_parsed ${proto} NAME_WLE)
|
||||||
|
FILE(TO_NATIVE_PATH ${PROTOBINDING_PATH}/gradido/${proto_parsed}.pb.h proto_parsed_native)
|
||||||
|
|
||||||
|
IF(${proto_native} IS_NEWER_THAN ${proto_parsed_native})
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND
|
||||||
|
${PROTOBUF_PROTOC_EXECUTABLE}
|
||||||
|
--proto_path=${GRADIDO_PROTO_MODEL_PATH}
|
||||||
|
--cpp_out=${PROTOBINDING_PATH}
|
||||||
|
${proto_native}
|
||||||
|
RESULT_VARIABLE rv
|
||||||
|
)
|
||||||
|
# Optional, but that can show the user if something have gone wrong with the proto generation
|
||||||
|
IF(${rv})
|
||||||
|
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ENDFOREACH(proto)
|
||||||
|
|
||||||
|
FOREACH(proto ${DATAMODEL_HEDERA_PROTOS})
|
||||||
|
FILE(TO_NATIVE_PATH ${proto} proto_native)
|
||||||
|
get_filename_component(proto_parsed ${proto} NAME_WLE)
|
||||||
|
FILE(TO_NATIVE_PATH ${PROTOBINDING_PATH}/hedera/${proto_parsed}.pb.h proto_parsed_native)
|
||||||
|
IF(${proto_native} IS_NEWER_THAN ${proto_parsed_native})
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND
|
||||||
|
${PROTOBUF_PROTOC_EXECUTABLE}
|
||||||
|
--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||||
|
--proto_path=${HEDERA_PROTO_MODEL_PATH}
|
||||||
|
--proto_path=${GOOGLE_PROTOBUF_INCLUDES}
|
||||||
|
--cpp_out=${PROTOBINDING_PATH}/hedera
|
||||||
|
--grpc_out ${PROTOBINDING_PATH}/hedera
|
||||||
|
${proto_native}
|
||||||
|
RESULT_VARIABLE rv
|
||||||
|
)
|
||||||
|
# Optional, but that can show the user if something have gone wrong with the proto generation
|
||||||
|
IF(${rv})
|
||||||
|
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDFOREACH(proto)
|
||||||
|
|
||||||
|
############################## include src files ###################################
|
||||||
|
#set(MYSQL_INCLUDE_DIR "dependencies/mariadb-connector-c/include")
|
||||||
|
|
||||||
|
FILE(GLOB CONTROLLER "src/cpp/controller/*.cpp" "src/cpp/controller/*.h")
|
||||||
|
FILE(GLOB TINF "dependencies/tinf/src/*.c" "dependencies/tinf/src/*.h")
|
||||||
|
FILE(GLOB HTTPInterface "src/cpp/HTTPInterface/*.h" "src/cpp/HTTPInterface/*.cpp")
|
||||||
|
FILE(GLOB JSONInterface "src/cpp/JSONInterface/*.h" "src/cpp/JSONInterface/*.cpp")
|
||||||
|
FILE(GLOB TASKS "src/cpp/tasks/*.cpp" "src/cpp/tasks/*.h")
|
||||||
|
FILE(GLOB SINGLETON_MANAGER "src/cpp/SingletonManager/*.h" "src/cpp/SingletonManager/*.cpp")
|
||||||
|
FILE(GLOB LIB_SRC "src/cpp/lib/*.h" "src/cpp/lib/*.cpp")
|
||||||
|
FILE(GLOB MODEL "src/cpp/model/*.h" "src/cpp/model/*.cpp")
|
||||||
|
FILE(GLOB MODEL_TABLE "src/cpp/model/table/*.h" "src/cpp/model/table/*.cpp")
|
||||||
|
FILE(GLOB MODEL_EMAIL "src/cpp/model/email/*.h" "src/cpp/model/email/*.cpp")
|
||||||
|
FILE(GLOB MODEL_HEDERA "src/cpp/model/hedera/*.h" "src/cpp/model/hedera/*.cpp")
|
||||||
|
FILE(GLOB MODEL_GRADIDO "src/cpp/model/gradido/*.h" "src/cpp/model/gradido/*.cpp")
|
||||||
|
FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp")
|
||||||
|
FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h")
|
||||||
|
FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h")
|
||||||
|
FILE(GLOB PROTO_GRADIDO "${PROTOBINDING_PATH}/gradido/*.cc" "${PROTOBINDING_PATH}/gradido/*.h")
|
||||||
|
FILE(GLOB PROTO_HEDERA "${PROTOBINDING_PATH}/hedera/*.cc" "${PROTOBINDING_PATH}/hedera/*.h")
|
||||||
|
|
||||||
|
# used only for test project
|
||||||
|
FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h")
|
||||||
|
FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h")
|
||||||
|
FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h")
|
||||||
|
FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h")
|
||||||
|
FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h")
|
||||||
|
|
||||||
|
SET(LOCAL_SRCS
|
||||||
|
${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface}
|
||||||
|
${JSONInterface} ${CRYPTO}
|
||||||
|
${MODEL} ${MODEL_TABLE} ${MODEL_EMAIL} ${MODEL_HEDERA} ${MODEL_GRADIDO}
|
||||||
|
${SINGLETON_MANAGER} ${LIB_SRC} ${MYSQL} ${TASKS}
|
||||||
|
${PROTO_GRADIDO} ${PROTO_HEDERA}
|
||||||
|
)
|
||||||
|
SET(LOCAL_TEST_SRC
|
||||||
|
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER}
|
||||||
|
)
|
||||||
|
aux_source_directory("src/cpp" LOCAL_SRCS)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
# src
|
||||||
|
source_group("controller" FILES ${CONTROLLER})
|
||||||
|
source_group("proto\\gradido" FILES ${PROTO_GRADIDO})
|
||||||
|
source_group("proto\\hedera" FILES ${PROTO_HEDERA})
|
||||||
|
source_group("tinf" FILES ${TINF})
|
||||||
|
source_group("Crypto" FILES ${CRYPTO})
|
||||||
|
source_group("tasks" FILES ${TASKS})
|
||||||
|
source_group("model\\table" FILES ${MODEL_TABLE})
|
||||||
|
source_group("model\\email" FILES ${MODEL_EMAIL})
|
||||||
|
source_group("model\\hedera" FILES ${MODEL_HEDERA})
|
||||||
|
source_group("model\\gradido" FILES ${MODEL_GRADIDO})
|
||||||
|
source_group("model" FILES ${MODEL})
|
||||||
|
source_group("mysql" FILES ${MYSQL})
|
||||||
|
source_group("SingletonManager" FILES ${SINGLETON_MANAGER})
|
||||||
|
source_group("lib" FILES ${LIB_SRC})
|
||||||
|
source_group("HTTP-Interface" FILES ${HTTPInterface})
|
||||||
|
source_group("Json-Interface" FILES ${JSONInterface})
|
||||||
|
source_group("Test\\crypto" FILES ${TEST_CRYPTO})
|
||||||
|
source_group("Test\\model\\table" FILES ${TEST_MODEL_TABLE})
|
||||||
|
source_group("Test\\model" FILES ${TEST_MODEL})
|
||||||
|
source_group("Test\\controller" FILES ${TEST_CONTROLLER})
|
||||||
|
source_group("Test" FILES ${TEST})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(Gradido_LoginServer ${LOCAL_SRCS})
|
||||||
|
|
||||||
|
############################## find mariadb ###################################
|
||||||
|
find_library(MYSQL_LIBRARIES mariadb PATHS "/usr/local/lib/mariadb" REQUIRED)
|
||||||
|
############################## config and add poco ###################################
|
||||||
|
set(BUILD_LIB_PATH "(/usr/local/lib")
|
||||||
|
|
||||||
|
IF(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||||
|
find_library(POCO_FOUNDATION_LIB PocoFoundationd PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_UTIL_LIB PocoUtild PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_NET_SSL_LIB PocoNetSSLd PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_DATA_LIB PocoDatad PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_JSON_LIB PocoJSONd PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_NET_LIB PocoNetd PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
message("use Poco Debug libs")
|
||||||
|
ELSE()
|
||||||
|
find_library(POCO_FOUNDATION_LIB PocoFoundation PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_UTIL_LIB PocoUtil PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_NET_SSL_LIB PocoNetSSL PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_DATA_LIB PocoData PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_JSON_LIB PocoJSON PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
find_library(POCO_NET_LIB PocoNet PATHS ${BUILD_LIB_PATH} REQUIRED)
|
||||||
|
message("use Poco Release libs")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
set(POCO_LIBS ${POCO_FOUNDATION_LIB} ${POCO_UTIL_LIB} ${POCO_NET_SSL_LIB} ${POCO_DATA_LIB} ${POCO_JSON_LIB} ${POCO_NET_LIB})
|
||||||
|
|
||||||
|
|
||||||
|
############################## build login server ###################################
|
||||||
|
|
||||||
|
target_link_libraries(Gradido_LoginServer gRPC::grpc++ ${PROTOBUF_LIBS} ${MYSQL_LIBRARIES} ${POCO_LIBS} sodium pthread)
|
||||||
|
|
||||||
@ -1,50 +1,45 @@
|
|||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
# Build release
|
# Build release
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
From conanio/gcc9 as release
|
FROM gradido/login_dependencies:alpine-release-1 as release
|
||||||
|
|
||||||
ENV DOCKER_WORKDIR="/code"
|
ENV DOCKER_WORKDIR="/code"
|
||||||
|
|
||||||
USER root
|
|
||||||
|
|
||||||
|
|
||||||
RUN mkdir -p ${DOCKER_WORKDIR}
|
|
||||||
WORKDIR ${DOCKER_WORKDIR}
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
|
|
||||||
COPY . .
|
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||||
|
COPY ./src ./src
|
||||||
RUN cd dependencies/mariadb-connector-c && \
|
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
|
||||||
mkdir build && \
|
COPY ./dependencies/spirit-po ./dependencies/spirit-po
|
||||||
cd build && \
|
COPY ./dependencies/tinf ./dependencies/tinf
|
||||||
cmake -DWITH_SSL=OFF ..
|
COPY ./scripts ./scripts
|
||||||
|
RUN cd scripts && \
|
||||||
RUN chmod +x compile_pot.sh && ./compile_pot.sh
|
chmod +x compile_pot.sh && \
|
||||||
|
./compile_pot.sh
|
||||||
|
|
||||||
RUN mkdir build && \
|
RUN mkdir build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
conan install .. --build=missing && \
|
cmake -DCMAKE_BUILD_TYPE=Release .. && \
|
||||||
cmake .. && \
|
|
||||||
make -j$(nproc) protoc grpc_cpp_plugin
|
|
||||||
|
|
||||||
RUN chmod +x unix_parse_proto.sh && ./unix_parse_proto.sh
|
|
||||||
|
|
||||||
RUN cd build && \
|
|
||||||
cmake .. && \
|
|
||||||
make -j$(nproc) Gradido_LoginServer
|
make -j$(nproc) Gradido_LoginServer
|
||||||
|
|
||||||
CMD ["./code"]
|
|
||||||
|
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
# run release
|
# run release
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
#From alpine:latest as login_server
|
#From alpine:latest as login_server
|
||||||
FROM alpine:latest as login_server
|
FROM alpine:3.13.5 as login_server
|
||||||
|
|
||||||
|
USER root
|
||||||
WORKDIR "/usr/bin"
|
WORKDIR "/usr/bin"
|
||||||
|
|
||||||
COPY --from=release /code/build/bin/Gradido_LoginServer /usr/bin/
|
COPY --from=release /code/build/bin/Gradido_LoginServer /usr/bin/
|
||||||
COPY --from=release /code/build/lib/libmariadb.so.3 /usr/lib/
|
|
||||||
|
COPY --from=release /usr/local/lib/mariadb/libmariadb.so.3 /usr/local/lib/
|
||||||
|
COPY --from=release /usr/local/lib/libPoco* /usr/local/lib/
|
||||||
|
COPY --from=release /usr/lib/libsodium.so.23 /usr/lib/
|
||||||
|
COPY --from=release /usr/lib/libstdc++.so.6 /usr/lib/
|
||||||
|
COPY --from=release /usr/lib/libgcc_s.so.1 /usr/lib/
|
||||||
|
|
||||||
|
|
||||||
RUN chmod +x /usr/bin/Gradido_LoginServer
|
RUN chmod +x /usr/bin/Gradido_LoginServer
|
||||||
ENTRYPOINT ["/usr/bin/Gradido_LoginServer"]
|
ENTRYPOINT ["/usr/bin/Gradido_LoginServer"]
|
||||||
CMD Gradido_LoginServer
|
#CMD Gradido_LoginServer
|
||||||
|
|||||||
14
login_server/Dockerfile.alpine-debug
Normal file
14
login_server/Dockerfile.alpine-debug
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM gradido/login_dependencies:alpine-debug-1 as login_server_alpine_debug
|
||||||
|
|
||||||
|
ENV DOCKER_WORKDIR="/code"
|
||||||
|
|
||||||
|
|
||||||
|
EXPOSE 1200
|
||||||
|
EXPOSE 1201
|
||||||
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
|
|
||||||
|
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||||
|
COPY ./scripts ./scripts
|
||||||
|
|
||||||
|
CMD cd scripts; ./build_debug.sh; cd ..; ./build/bin/Gradido_LoginServer
|
||||||
|
|
||||||
@ -1,3 +1,19 @@
|
|||||||
|
#########################################################################################################
|
||||||
|
# cmake
|
||||||
|
#########################################################################################################
|
||||||
|
FROM gcc:9 as cmake-gcc-9
|
||||||
|
|
||||||
|
ENV DOCKER_WORKDIR="/code"
|
||||||
|
RUN mkdir -p ${DOCKER_WORKDIR}
|
||||||
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN git clone https://github.com/Kitware/CMake.git --branch=v3.19.8 \
|
||||||
|
&& cd CMake \
|
||||||
|
&& ./bootstrap \
|
||||||
|
&& make -j$(nproc) \
|
||||||
|
&& make install
|
||||||
|
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
# Build debug
|
# Build debug
|
||||||
@ -11,8 +27,9 @@ USER root
|
|||||||
WORKDIR ${DOCKER_WORKDIR}
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN chmod +x unix_parse_proto.sh
|
RUN cd scripts \
|
||||||
RUN chmod +x compile_pot.sh
|
&& chmod +x ./prepare_build.sh \
|
||||||
|
&& ./prepare_build.sh
|
||||||
|
|
||||||
RUN ./compile_pot.sh
|
RUN ./compile_pot.sh
|
||||||
RUN ./unix_parse_proto.sh
|
RUN ./unix_parse_proto.sh
|
||||||
@ -37,6 +54,7 @@ VOLUME /code/src
|
|||||||
EXPOSE 1200
|
EXPOSE 1200
|
||||||
EXPOSE 1201
|
EXPOSE 1201
|
||||||
WORKDIR ${DOCKER_WORKDIR}
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
RUN chmod +x ./Dockerfiles/build_and_run.sh
|
RUN chmod +x ./scripts/build_and_run.sh
|
||||||
|
|
||||||
CMD ./Dockerfiles/build_and_run.sh; ./build_vol/bin/Gradido_LoginServer
|
CMD ./Dockerfiles/build_and_run.sh; ./build_vol/bin/Gradido_LoginServer
|
||||||
|
|
||||||
|
|||||||
@ -1,56 +1,93 @@
|
|||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
# debug build preparation
|
# gcc 9 with libssl
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
From conanio/gcc9 as build_debug_preparation
|
FROM gcc:9 as gcc_9_libssl
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends libssl-dev libboost-dev && \
|
||||||
|
apt-get autoclean && \
|
||||||
|
apt-get autoremove && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
|
#########################################################################################################
|
||||||
|
# gcc 9 cmake
|
||||||
|
#########################################################################################################
|
||||||
|
FROM gcc_9_libssl as gcc_9_cmake
|
||||||
|
|
||||||
|
USER root
|
||||||
ENV DOCKER_WORKDIR="/code"
|
ENV DOCKER_WORKDIR="/code"
|
||||||
|
|
||||||
RUN mkdir -p ${DOCKER_WORKDIR}
|
RUN mkdir -p ${DOCKER_WORKDIR}
|
||||||
WORKDIR ${DOCKER_WORKDIR}
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
|
|
||||||
|
|
||||||
|
RUN git clone https://github.com/Kitware/CMake.git --branch=v3.19.8 && \
|
||||||
|
cd CMake && \
|
||||||
|
./bootstrap --parallel=$(nproc) && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install && \
|
||||||
|
cd .. && \
|
||||||
|
rm -rf CMake
|
||||||
|
|
||||||
|
#########################################################################################################
|
||||||
|
# debug build preparation
|
||||||
|
#########################################################################################################
|
||||||
|
FROM gcc_9_libssl as build_debug_dependencies
|
||||||
|
|
||||||
|
USER root
|
||||||
|
ENV DOCKER_WORKDIR="/code"
|
||||||
|
|
||||||
|
RUN mkdir -p ${DOCKER_WORKDIR}
|
||||||
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
|
|
||||||
|
# copy CMake from last stage
|
||||||
|
COPY --from=gcc_9_cmake /usr/local/bin/cmake /usr/local/bin/cmake
|
||||||
|
COPY --from=gcc_9_cmake /usr/local/share/cmake-3.19/Modules /usr/local/share/cmake-3.19/Modules
|
||||||
|
COPY --from=gcc_9_cmake /usr/local/share/cmake-3.19/Templates /usr/local/share/cmake-3.19/Templates
|
||||||
|
|
||||||
COPY ./dependencies ./dependencies
|
COPY ./dependencies ./dependencies
|
||||||
COPY ./conanfile.txt ./conanfile.txt
|
COPY ./scripts ./scripts
|
||||||
|
|
||||||
|
|
||||||
RUN cd dependencies/mariadb-connector-c && \
|
|
||||||
mkdir build && \
|
|
||||||
cd build && \
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_SSL=OFF ..
|
|
||||||
|
|
||||||
|
|
||||||
RUN mkdir build && \
|
|
||||||
cd build && \
|
|
||||||
conan install .. --build=missing -s build_type=Debug
|
|
||||||
|
|
||||||
|
|
||||||
#########################################################################################################
|
|
||||||
# debug build proto and grpc
|
|
||||||
#########################################################################################################
|
|
||||||
From build_debug_preparation as proto_grpc
|
|
||||||
|
|
||||||
ENV DOCKER_WORKDIR="/code"
|
|
||||||
WORKDIR ${DOCKER_WORKDIR}
|
|
||||||
|
|
||||||
COPY ./CMakeLists.txt .
|
COPY ./CMakeLists.txt .
|
||||||
RUN cd build && \
|
COPY ./src ./src
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug .. && \
|
|
||||||
make -j${CPU_COUNT} protoc grpc_cpp_plugin
|
|
||||||
|
RUN cd scripts && \
|
||||||
|
chmod +x ./prepare_build.sh && \
|
||||||
|
./prepare_build.sh && \
|
||||||
|
mkdir ../build && \
|
||||||
|
chmod +x ./build_debug.sh && \
|
||||||
|
./build_debug.sh
|
||||||
|
|
||||||
|
# remove unneccessary stuff
|
||||||
|
RUN rm -rf build/bin/Gradido_LoginServer
|
||||||
|
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
# parse proto and gettext
|
# debug build
|
||||||
#########################################################################################################
|
#########################################################################################################
|
||||||
From proto_grpc as proto_parse
|
FROM gcc_9_libssl as build_debug
|
||||||
|
|
||||||
|
USER root
|
||||||
ENV DOCKER_WORKDIR="/code"
|
ENV DOCKER_WORKDIR="/code"
|
||||||
|
|
||||||
|
RUN mkdir -p ${DOCKER_WORKDIR}
|
||||||
WORKDIR ${DOCKER_WORKDIR}
|
WORKDIR ${DOCKER_WORKDIR}
|
||||||
|
|
||||||
RUN mkdir src && \
|
|
||||||
cd src && \
|
|
||||||
mkdir cpp
|
|
||||||
COPY ./src/proto ./src/proto
|
|
||||||
COPY ./unix_parse_proto.sh .
|
|
||||||
|
|
||||||
RUN chmod +x unix_parse_proto.sh && \
|
# copy CMake from last stage
|
||||||
./unix_parse_proto.sh
|
COPY --from=build_debug_dependencies /usr/local/bin/cmake /usr/local/bin/cmake
|
||||||
|
COPY --from=build_debug_dependencies /usr/local/share/cmake-3.19 /usr/local/share/cmake-3.19
|
||||||
|
|
||||||
|
COPY --from=build_debug_dependencies /code/build/bin /code/build/bin
|
||||||
|
COPY --from=build_debug_dependencies /code/build/lib /code/build/lib
|
||||||
|
|
||||||
|
# grpc
|
||||||
|
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/lib /build/dependencies/grpc/lib
|
||||||
|
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/protobuf/lib /build/dependencies/grpc/third_party/protobuf/lib
|
||||||
|
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/re2/lib /build/dependencies/grpc/third_party/re2/lib
|
||||||
|
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/zlib/lib /build/dependencies/grpc/third_party/zlib/lib
|
||||||
|
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/cares/cares/lib /build/dependencies/grpc/third_party/cares/cares/lib
|
||||||
|
COPY --from=build_debug_dependencies /code/build/dependencies/mariadb-connector-c/libmariadb/lib /build/dependencies/mariadb-connector-c/libmariadb/lib
|
||||||
|
|
||||||
|
|||||||
79
login_server/Dockerfiles/Dockerfile.dependencies-alpine
Normal file
79
login_server/Dockerfiles/Dockerfile.dependencies-alpine
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
##### BUILD-ENV #####
|
||||||
|
FROM alpine:3.13.5 as alpine-build
|
||||||
|
|
||||||
|
RUN apk add --update --no-cache icu-dev
|
||||||
|
RUN apk add --no-cache git openssl-dev make gcc musl-dev g++ linux-headers libintl gettext-dev boost-dev libsodium-dev
|
||||||
|
|
||||||
|
|
||||||
|
##### CMAKE #####
|
||||||
|
FROM alpine-build as alpine-gxx-cmake
|
||||||
|
|
||||||
|
RUN git clone https://github.com/Kitware/CMake.git --branch=v3.19.8 && \
|
||||||
|
cd CMake && \
|
||||||
|
./bootstrap --parallel=$(nproc) && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
######### BUILD grpc ##############
|
||||||
|
FROM alpine-gxx-cmake as alpine-gxx-grpc
|
||||||
|
|
||||||
|
ARG BUILD_TYPE=Debug
|
||||||
|
|
||||||
|
RUN git clone https://github.com/grpc/grpc.git --branch=v1.37.0 --recursive -j4 && \
|
||||||
|
cd grpc && \
|
||||||
|
mkdir build && cd build && \
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
# abseil don't install themself correctly
|
||||||
|
RUN cp -r grpc/third_party/abseil-cpp/absl /usr/local/include/
|
||||||
|
|
||||||
|
# protobuf libs missing after make install
|
||||||
|
RUN cp grpc/build/third_party/protobuf/*.a /usr/local/lib/
|
||||||
|
|
||||||
|
######### BUILD poco ##############
|
||||||
|
FROM alpine-gxx-cmake as alpine-gxx-poco
|
||||||
|
|
||||||
|
ARG BUILD_TYPE=Debug
|
||||||
|
|
||||||
|
RUN git clone https://github.com/pocoproject/poco.git --recursive && \
|
||||||
|
cd poco && \
|
||||||
|
git checkout poco-1.9.4-release && \
|
||||||
|
mkdir cmake-build && cd cmake-build && \
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
######### BUILD mariadb ###########
|
||||||
|
FROM alpine-gxx-cmake as alpine-gxx-mariadb-connector
|
||||||
|
|
||||||
|
ARG BUILD_TYPE=Debug
|
||||||
|
|
||||||
|
RUN git clone https://github.com/mariadb-corporation/mariadb-connector-c.git && \
|
||||||
|
cd mariadb-connector-c && \
|
||||||
|
git checkout 159540f && \
|
||||||
|
mkdir build && cd build && \
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
#########################################################################################################
|
||||||
|
# builded libs and binaries
|
||||||
|
#########################################################################################################
|
||||||
|
FROM alpine-build as alpine-libs
|
||||||
|
|
||||||
|
# copy CMake from cmake stage
|
||||||
|
COPY --from=alpine-gxx-cmake /usr/local/bin/cmake /usr/local/bin/cmake
|
||||||
|
COPY --from=alpine-gxx-cmake /usr/local/share/cmake-3.19/Modules /usr/local/share/cmake-3.19/Modules
|
||||||
|
COPY --from=alpine-gxx-cmake /usr/local/share/cmake-3.19/Templates /usr/local/share/cmake-3.19/Templates
|
||||||
|
|
||||||
|
# copy from grpc
|
||||||
|
COPY --from=alpine-gxx-grpc /usr/local /usr/local
|
||||||
|
|
||||||
|
|
||||||
|
# COPY from poco
|
||||||
|
COPY --from=alpine-gxx-poco /usr/local /usr/local
|
||||||
|
|
||||||
|
# COPY from mariadb
|
||||||
|
COPY --from=alpine-gxx-mariadb-connector /usr/local /usr/local
|
||||||
|
|
||||||
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cp build/conan* build_vol/
|
|
||||||
|
|
||||||
cd build_vol
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
make -j${CPU_COUNT} protoc grpc_cpp_plugin
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
if [ ! -f "./src/cpp/proto/gradido/TransactionBody.pb.h" ] ; then
|
|
||||||
chmod +x unix_parse_proto.sh
|
|
||||||
echo "parse proto files"
|
|
||||||
./unix_parse_proto.sh
|
|
||||||
fi
|
|
||||||
chmod +x compile_pot.sh
|
|
||||||
./compile_pot.sh
|
|
||||||
|
|
||||||
cd build_vol
|
|
||||||
cmake ..
|
|
||||||
make -j$(nproc) Gradido_LoginServer
|
|
||||||
#echo "building done"
|
|
||||||
chmod +x ./bin/Gradido_LoginServer
|
|
||||||
#./bin/Gradido_LoginServer
|
|
||||||
|
|
||||||
|
|
||||||
: '
|
|
||||||
cd build
|
|
||||||
conan install .. --build=missing -s build_type=Debug
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
make -j${CPU_COUNT} protoc grpc_cpp_plugin
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
if [ ! -d "./src/cpp/proto/hedera" ] ; then
|
|
||||||
#if [ ! -f "./src/cpp/proto/gradido/TransactionBody.pb.h"] ; then
|
|
||||||
chmod +x unix_parse_proto.sh
|
|
||||||
./unix_parse_proto.sh
|
|
||||||
fi
|
|
||||||
chmod +x compile_pot.sh
|
|
||||||
|
|
||||||
./compile_pot.sh
|
|
||||||
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
make -j$(nproc) Gradido_LoginServer
|
|
||||||
#echo "building done"
|
|
||||||
chmod +x ./bin/Gradido_LoginServer
|
|
||||||
#./bin/Gradido_LoginServer
|
|
||||||
'
|
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
sudo apt install libsodium-dev
|
||||||
|
|
||||||
# get dependencies
|
# get dependencies
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
xgettext -D src/cpp -p src/LOCALE -o messages.pot --from-code=UTF-8 --files-from=files_to_translate.txt
|
|
||||||
@ -2,12 +2,7 @@
|
|||||||
Poco/1.9.4@pocoproject/stable
|
Poco/1.9.4@pocoproject/stable
|
||||||
libsodium/1.0.18@bincrafters/stable
|
libsodium/1.0.18@bincrafters/stable
|
||||||
boost/1.71.0@conan/stable
|
boost/1.71.0@conan/stable
|
||||||
gtest/1.8.1@bincrafters/stable
|
|
||||||
|
|
||||||
[generators]
|
[generators]
|
||||||
cmake
|
cmake
|
||||||
|
|
||||||
[options]
|
|
||||||
Poco:enable_data_sqlite=False
|
|
||||||
Poco:enable_mongodb=False
|
|
||||||
Poco:enable_redis=False
|
|
||||||
|
|||||||
1
login_server/dependencies/libsodium
Submodule
1
login_server/dependencies/libsodium
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 8aedf4733884a25434b5c17c79c7e7dee27e6eb0
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 3fc3e5f5b8462f7666952b43381383a79b8b5d92
|
Subproject commit b95393dcc3640807838e8323b4e600e54d2e8116
|
||||||
@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
if [ ! -d "./src/cpp/proto" ] ; then
|
|
||||||
mkdir ./src/cpp/proto
|
|
||||||
fi
|
|
||||||
if [ ! -d "./src/cpp/proto/gradido" ] ; then
|
|
||||||
mkdir ./src/cpp/proto/gradido
|
|
||||||
fi
|
|
||||||
|
|
||||||
./protoc --cpp_out=./src/cpp/proto --proto_path=./src/proto ./src/proto/gradido/*.proto
|
|
||||||
|
|
||||||
if [ ! -d "./src/cpp/proto/hedera" ] ; then
|
|
||||||
mkdir ./src/cpp/proto/hedera
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
./protoc --plugin=protoc-gen-grpc=./grpc_cpp_plugin.exe --cpp_out=./src/cpp/proto/hedera --grpc_out=./src/cpp/proto/hedera --proto_path=./src/proto/hedera/hedera-protobuf/src/main/proto ./src/proto/hedera/hedera-protobuf/src/main/proto/*.proto
|
|
||||||
12
login_server/scripts/build_debug.sh
Executable file
12
login_server/scripts/build_debug.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cd ../scripts
|
||||||
|
|
||||||
|
chmod +x compile_pot.sh
|
||||||
|
./compile_pot.sh
|
||||||
|
|
||||||
|
cd ../build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
|
make -j$(nproc) Gradido_LoginServer
|
||||||
|
|
||||||
|
chmod +x ./bin/Gradido_LoginServer
|
||||||
2
login_server/scripts/compile_pot.sh
Executable file
2
login_server/scripts/compile_pot.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
xgettext -D ../src/cpp -p ../src/LOCALE -o messages.pot --from-code=UTF-8 --files-from=files_to_translate.txt
|
||||||
@ -7,3 +7,4 @@ model/email/Email.cpp
|
|||||||
model/email/EmailCustomReply.cpp
|
model/email/EmailCustomReply.cpp
|
||||||
model/email/EmailNotificationCreation.cpp
|
model/email/EmailNotificationCreation.cpp
|
||||||
model/email/EmailNotificationTransfer.cpp
|
model/email/EmailNotificationTransfer.cpp
|
||||||
|
SingletonManager/SessionManager.cpp
|
||||||
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