diff --git a/CHANGELOG.md b/CHANGELOG.md
index e949f98e3..7010d71fe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,22 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
+#### [1.1.1](https://github.com/gradido/gradido/compare/1.1.0...1.1.1)
+
+- Auto deploy [`#580`](https://github.com/gradido/gradido/pull/580)
+- update transfer email text [`#574`](https://github.com/gradido/gradido/pull/574)
+- update mysql because tuple has changed [`#576`](https://github.com/gradido/gradido/pull/576)
+- Login fix pending transactions [`#578`](https://github.com/gradido/gradido/pull/578)
+- add test to prevent bug in future [`630d667`](https://github.com/gradido/gradido/commit/630d667e996870a1bf9aa9586b0467d58419e525)
+- use standard path. add nginx example [`ac249b4`](https://github.com/gradido/gradido/commit/ac249b46830a8039aec52d30b48084b50a264b6f)
+- add autodeploy bash scripts [`f49cf4d`](https://github.com/gradido/gradido/commit/f49cf4d7f8054d87efa1e12055a7ef0c6d3b9872)
+
#### [1.1.0](https://github.com/gradido/gradido/compare/1.0.2...1.1.0)
+> 17 June 2021
+
+- add first error additional as msg [`#573`](https://github.com/gradido/gradido/pull/573)
+- fix: Remove Grouping for Max Error [`#572`](https://github.com/gradido/gradido/pull/572)
- fix: API Call for Reset Password [`#571`](https://github.com/gradido/gradido/pull/571)
- Login reset password [`#570`](https://github.com/gradido/gradido/pull/570)
- Hide unuse components in profil [`#566`](https://github.com/gradido/gradido/pull/566)
diff --git a/community_server/src/Template/Email/text/notification_transfer.ctp b/community_server/src/Template/Email/text/notification_transfer.ctp
index 155304c2c..05df9695d 100644
--- a/community_server/src/Template/Email/text/notification_transfer.ctp
+++ b/community_server/src/Template/Email/text/notification_transfer.ctp
@@ -8,14 +8,19 @@
$this->assign('title', __('Gradido Überweisung'));
$receiverNames = $receiverUser->first_name . ' ' . $receiverUser->last_name;
$senderNames = $senderUser->first_name . ' ' . $senderUser->last_name;
+$senderNamesEmail = $senderUser->getEmailWithName();
?>= __('Hallo') ?> = $receiverNames ?>,
-= __('Du hast soeben {0} von {1} erhalten.', $this->element('printGradido', ['number' => $gdd_cent, 'raw' => true]), $senderNames) ?>
+= __('Du hast soeben {0} von {1} erhalten.', $this->element('printGradido', ['number' => $gdd_cent, 'raw' => true]), $senderNamesEmail) ?>
= __('{0} schreibt:', $senderNames) ?>
= $memo ?>
= __('Bitte antworte nicht auf diese E-Mail!'); ?>
+= __('Wenn Du ') . $senderNames . __(' per E-Mail antworten willst, schreibe stattdessen an die Adresse: '); ?>
+
+= $senderUser->email ?>
+
= __('Mit freundlichen Grüßen'); ?>
Gradido Community Server
\ No newline at end of file
diff --git a/deployment/bare_metal/build_and_start_login_server.sh b/deployment/bare_metal/build_and_start_login_server.sh
new file mode 100755
index 000000000..b97d1d4a9
--- /dev/null
+++ b/deployment/bare_metal/build_and_start_login_server.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# stop login_server running in screen
+screen -XS login quit
+
+# rebuild login-server
+cd ../../login_server
+if [ ! -d "./build" ] ; then
+ cd scripts
+ ./prepare_build.sh
+ cd ..
+fi
+cd build
+cmake ..
+make -j$(nproc) Gradido_LoginServer
+
+# rebuild locales
+cd ../scripts
+./compile_pot.sh
+cd ../src/LOCALE
+cp *.mo *.po /etc/grd_login/LOCALE/
+
+cd ../../build/bin
+
+# start login-server
+screen -dmS 'login_server' bash -c './Gradido_LoginServer'
+
+
+
diff --git a/deployment/bare_metal/build_frontend.sh b/deployment/bare_metal/build_frontend.sh
new file mode 100755
index 000000000..fc0feb747
--- /dev/null
+++ b/deployment/bare_metal/build_frontend.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# For that to work, node v12.19.0 needs to be installed with nvm for root
+# or NPM_BIN Path and NVM_DIR must be adjusted
+
+cd /var/www/html/gradido/frontend
+
+NPM_BIN=/root/.nvm/versions/node/v12.19.0/bin/npm
+
+export NVM_DIR="/root/.nvm"
+[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
+
+$NPM_BIN install
+$NPM_BIN run build
+# prezip for faster deliver throw nginx
+cd dist
+find . -type f -name "*.css" -exec gzip -9 -k {} \;
+find . -type f -name "*.js" -exec gzip -9 -k {} \;
diff --git a/deployment/bare_metal/nginx/sites-available/gradido b/deployment/bare_metal/nginx/sites-available/gradido
new file mode 100644
index 000000000..c32d82483
--- /dev/null
+++ b/deployment/bare_metal/nginx/sites-available/gradido
@@ -0,0 +1,73 @@
+server {
+ server_name _;
+ listen 80;
+ listen [::]:80;
+
+ include /etc/nginx/common/protect.conf;
+ include /etc/nginx/common/protect_add_header.conf;
+
+ root /var/www/html/gradido/community_server/webroot;
+ index index.php;
+
+ gzip_static on;
+
+
+ location ~ \.php$ {
+ include snippets/fastcgi-php.conf;
+ fastcgi_pass unix:/run/php/php7.4-fpm.sock;
+ }
+
+ location ~ /\.ht {
+ deny all;
+ }
+
+ location /vue {
+ alias /var/www/html/gradido/frontend/dist;
+ index index.html;
+
+ location ~* \.(png)$ {
+ expires 39d;
+ }
+ try_files $uri $uri/ /index.html = 404;
+ }
+
+ location /account {
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_cache_bypass $http_upgrade;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header Host $host;
+ rewrite /account/(.*) /$1 break;
+
+ proxy_pass http://127.0.0.1:1200;
+ proxy_redirect off;
+
+
+ }
+
+ location /login_api {
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_cache_bypass $http_upgrade;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header Host $host;
+ rewrite /login_api/(.*) /$1 break;
+
+ proxy_pass http://127.0.0.1:1201;
+ proxy_redirect off;
+
+
+ }
+
+
+ location / {
+ try_files $uri $uri/ /index.php?$args;
+ }
+
+ access_log /var/log/nginx/access.log main;
+
+}
diff --git a/deployment/bare_metal/nginx/sites-available/gradido_updating b/deployment/bare_metal/nginx/sites-available/gradido_updating
new file mode 100644
index 000000000..df07e3715
--- /dev/null
+++ b/deployment/bare_metal/nginx/sites-available/gradido_updating
@@ -0,0 +1,29 @@
+
+server {
+ server_name _;
+ listen 80;
+ listen [::]:80;
+
+ include /etc/nginx/common/protect.conf;
+ include /etc/nginx/common/protect_add_header.conf;
+
+ root /var/www/html/;
+ index updating.html;
+
+ location /account {
+ alias /var/www/html/;
+ index updating.html;
+ }
+ location /vue {
+ alias /var/www/html/;
+ index updating.html;
+ }
+
+ location ~ /\.ht {
+ deny all;
+ }
+
+ access_log /var/log/nginx/access.log main;
+
+}
+
diff --git a/deployment/bare_metal/nginx/updating_original.html b/deployment/bare_metal/nginx/updating_original.html
new file mode 100644
index 000000000..8975e3970
--- /dev/null
+++ b/deployment/bare_metal/nginx/updating_original.html
@@ -0,0 +1 @@
+Gradido Servers are updating..., please stand by and try again in some minutes
diff --git a/deployment/bare_metal/update_all.sh b/deployment/bare_metal/update_all.sh
new file mode 100755
index 000000000..b065a16d4
--- /dev/null
+++ b/deployment/bare_metal/update_all.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+EMPTY_UPDATE_HTML=/var/www/html/updating_original.html
+UPDATE_HTML=/var/www/html/updating.html
+LOCK_FILE=/root/relay.lock
+PROJECT_PATH=/var/www/html/gradido
+SITE_CONFIG=stage1
+UPDATE_SITE_CONFIG=stage1_updating
+
+# this script can be called for example from webhookrelay.com relay
+# to auto-deploy automatic after a update to the master branch
+
+if [ -f $LOCK_FILE ] ; then
+ retVal="Already building!"
+ return "${retVal}" 2>/dev/null || exit "${retVal}"
+fi
+
+touch $LOCK_FILE
+
+# start with nearly empty html
+# needed a nearly empty html page in the folder
+cp $EMPTY_UPDATE_HTML $UPDATE_HTML
+
+# let nginx showing a update page
+# needed nginx site-configs in nginx folders
+# gradido for running gradido servers
+# gradido_updating for showing upddate.html idealy for all pathes
+rm /etc/nginx/sites-enabled/$SITE_CONFIG
+ln -s /etc/nginx/sites-available/$UPDATE_SITE_CONFIG /etc/nginx/sites-enabled/
+service nginx restart
+
+# stop login server
+screen -XS login quit
+echo 'starting with git pull
' >> $UPDATE_HTML
+cd $PROJECT_PATH
+# git checkout -f master
+git pull
+cd deployment/bare_metal
+echo 'update schemas' >> $UPDATE_HTML
+./update_db_schemas.sh
+echo 'starting with rebuilding login-server
' >> $UPDATE_HTML
+./build_and_start_login_server.sh
+echo 'starting with rebuilding frontend
' >> $UPDATE_HTML
+./build_frontend.sh
+
+
+# let nginx showing gradido
+rm /etc/nginx/sites-enabled/$UPDATE_SITE_CONFIG
+ln -s /etc/nginx/sites-available/$SITE_CONFIG /etc/nginx/sites-enabled/
+service nginx restart
+
+rm $LOCK_FILE
+
diff --git a/deployment/bare_metal/update_db_schemas.sh b/deployment/bare_metal/update_db_schemas.sh
new file mode 100755
index 000000000..48cba596b
--- /dev/null
+++ b/deployment/bare_metal/update_db_schemas.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# For that to work skeema needed to be installed on system
+# in login_server/skeema and community_server/db/skeema skeema configuration files need to be there also in the subfolders
+# Update DB Schemas (only the schemas, not the data)
+
+cd ../../login_server/skeema
+skeema push --allow-unsafe
+cd ../../community_server/db/skeema
+skeema push --allow-unsafe
diff --git a/frontend/package.json b/frontend/package.json
index b53826746..04893215d 100755
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "bootstrap-vue-gradido-wallet",
- "version": "1.1.0",
+ "version": "1.1.1",
"private": true,
"scripts": {
"start": "node run/server.js",
diff --git a/login_server/src/cpp/JSONInterface/JsonGetUsers.cpp b/login_server/src/cpp/JSONInterface/JsonGetUsers.cpp
index 77f5e0a24..5d0f963d4 100644
--- a/login_server/src/cpp/JSONInterface/JsonGetUsers.cpp
+++ b/login_server/src/cpp/JSONInterface/JsonGetUsers.cpp
@@ -93,10 +93,10 @@ Poco::JSON::Object* JsonGetUsers::handle(Poco::Dynamic::Var params)
result->set("state", "success");
//Poco::JSON::Object jsonResultObject;
- Poco::JSON::Array jsonUsersArray;
+ Poco::JSON::Array::Ptr jsonUsersArray = new Poco::JSON::Array;
for (auto it = results.begin(); it != results.end(); it++) {
- jsonUsersArray.add((*it)->getJson());
+ jsonUsersArray->add((*it)->getJson());
(*it)->release();
}
results.clear();
diff --git a/login_server/src/cpp/controller/User.cpp b/login_server/src/cpp/controller/User.cpp
index 0ca3ac988..955b780d0 100644
--- a/login_server/src/cpp/controller/User.cpp
+++ b/login_server/src/cpp/controller/User.cpp
@@ -65,11 +65,11 @@ namespace controller {
std::vector fieldNames = { "first_name", "last_name", "email", "email_checked" };
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
std::vector results;
+ // Poco::Tuple, Poco::DateTime, int, int, int> UserTuple;
using namespace Poco::Data::Keywords;
Poco::Data::Statement select(session);
- // typedef Poco::Tuple, Poco::DateTime, int, int, int> UserTuple;
- select << "SELECT id, first_name, last_name, email, username, pubkey, created, email_checked, disabled, group_id FROM " << db->getTableName();
+ select << "SELECT id, first_name, last_name, email, username, description, pubkey, created, email_checked, disabled, group_id FROM " << db->getTableName();
select << " where email_checked = 0 ";
select, into(resultFromDB);
if (searchString != "") {
diff --git a/login_server/src/cpp/model/gradido/Transaction.cpp b/login_server/src/cpp/model/gradido/Transaction.cpp
index e3c4ada0f..00bfc92ac 100644
--- a/login_server/src/cpp/model/gradido/Transaction.cpp
+++ b/login_server/src/cpp/model/gradido/Transaction.cpp
@@ -361,6 +361,7 @@ namespace model {
auto pt = PendingTasksManager::getInstance();
pt->removeTask(Poco::AutoPtr(this, true));
+ deleteFromDB();
return 1 == runSendTransaction();
//return true;
}
diff --git a/login_server/src/cpp/test/JSONInterface/TestJsonGetUsers.cpp b/login_server/src/cpp/test/JSONInterface/TestJsonGetUsers.cpp
new file mode 100644
index 000000000..941896de6
--- /dev/null
+++ b/login_server/src/cpp/test/JSONInterface/TestJsonGetUsers.cpp
@@ -0,0 +1,144 @@
+#include "gtest/gtest.h"
+#include "SingletonManager/SessionManager.h"
+
+#include "Poco/JSON/Object.h"
+
+#include "JSONInterface/JsonGetUsers.h"
+
+TEST(TestJsonGetUsers, NO_ADMIN)
+{
+ auto sm = SessionManager::getInstance();
+ auto session = sm->getNewSession();
+ auto user = controller::User::create();
+ user->load("d_schultz32@gmx.de");
+ session->setUser(user);
+
+ JsonGetUsers jsonCall;
+ Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
+ params->set("search", "b");
+ params->set("session_id", session->getHandle());
+ auto result = jsonCall.handle(params);
+
+ auto state = result->get("state");
+ ASSERT_FALSE(state.isEmpty());
+ ASSERT_TRUE(state.isString());
+ ASSERT_EQ(state.toString(), "wrong role");
+
+ auto msg = result->get("msg");
+ ASSERT_FALSE(msg.isEmpty());
+ ASSERT_TRUE(msg.isString());
+ ASSERT_EQ(msg.toString(), "User hasn't correct role");
+
+ sm->releaseSession(session);
+}
+
+TEST(TestJsonGetUsers, INVALID_SESSION)
+{
+
+ JsonGetUsers jsonCall;
+ Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
+ params->set("search", "");
+ params->set("session_id", rand());
+ auto result = jsonCall.handle(params);
+
+ auto state = result->get("state");
+ ASSERT_FALSE(state.isEmpty());
+ ASSERT_TRUE(state.isString());
+ ASSERT_EQ(state.toString(), "not found");
+
+ auto msg = result->get("msg");
+ ASSERT_FALSE(msg.isEmpty());
+ ASSERT_TRUE(msg.isString());
+ ASSERT_EQ(msg.toString(), "Session not found");
+}
+
+TEST(TestJsonGetUsers, EMPTY_SEARCH)
+{
+ auto sm = SessionManager::getInstance();
+ auto session = sm->getNewSession();
+ auto user = controller::User::create();
+ user->load("Tiger_231@yahoo.com");
+ session->setUser(user);
+
+ JsonGetUsers jsonCall;
+ Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
+ params->set("search", "");
+ params->set("session_id", session->getHandle());
+ auto result = jsonCall.handle(params);
+
+ auto state = result->get("state");
+ ASSERT_FALSE(state.isEmpty());
+ ASSERT_TRUE(state.isString());
+ ASSERT_EQ(state.toString(), "not found");
+
+ auto msg = result->get("msg");
+ ASSERT_FALSE(msg.isEmpty());
+ ASSERT_TRUE(msg.isString());
+ ASSERT_EQ(msg.toString(), "Search string is empty and account_state is all or empty");
+
+ sm->releaseSession(session);
+}
+
+TEST(TestJsonGetUsers, VALID_SEARCH)
+{
+ auto sm = SessionManager::getInstance();
+ auto session = sm->getNewSession();
+ auto user = controller::User::create();
+ user->load("Tiger_231@yahoo.com");
+ session->setUser(user);
+
+ JsonGetUsers jsonCall;
+ Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
+ params->set("search", "a");
+ params->set("session_id", session->getHandle());
+ auto result = jsonCall.handle(params);
+
+ auto state = result->get("state");
+ ASSERT_FALSE(state.isEmpty());
+ ASSERT_TRUE(state.isString());
+ ASSERT_EQ(state.toString(), "success");
+
+ auto msg = result->get("msg");
+ ASSERT_TRUE(msg.isEmpty());
+
+ EXPECT_TRUE(result->isArray("users"));
+ auto users = result->getArray("users");
+ ASSERT_FALSE(users.isNull());
+
+ ASSERT_EQ(users->size(), 6);
+
+ sm->releaseSession(session);
+}
+
+TEST(TestJsonGetUsers, VALID_STATE_SEARCH)
+{
+ auto sm = SessionManager::getInstance();
+ auto session = sm->getNewSession();
+ auto user = controller::User::create();
+ user->load("Tiger_231@yahoo.com");
+ session->setUser(user);
+
+ JsonGetUsers jsonCall;
+ Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
+ params->set("search", "");
+ params->set("account_state", "email not activated");
+ params->set("session_id", session->getHandle());
+ auto result = jsonCall.handle(params);
+
+ auto state = result->get("state");
+ ASSERT_FALSE(state.isEmpty());
+ ASSERT_TRUE(state.isString());
+ ASSERT_EQ(state.toString(), "success");
+
+ auto msg = result->get("msg");
+ ASSERT_TRUE(msg.isEmpty());
+
+ EXPECT_TRUE(result->isArray("users"));
+ auto users = result->getArray("users");
+ ASSERT_FALSE(users.isNull());
+
+ ASSERT_EQ(users->size(), 1);
+
+ sm->releaseSession(session);
+}
+
diff --git a/login_server/src/cpp/test/main.cpp b/login_server/src/cpp/test/main.cpp
index 848a463bf..b98c86e61 100644
--- a/login_server/src/cpp/test/main.cpp
+++ b/login_server/src/cpp/test/main.cpp
@@ -177,9 +177,10 @@ int load(int argc, char* argv[]) {
// clean up and fill db
std::string tables[] = {
"groups",
- "users"
+ "users",
+ "user_roles"
};
- for (int i = 0; i < 2; i++) {
+ for (int i = 0; i < 3; i++) {
if (runMysql("TRUNCATE " + tables[i])) {
return -1;
}
@@ -204,7 +205,15 @@ int load(int argc, char* argv[]) {
<< "(4, 'Nikola_Tesla@email.de', 'Nikola', 'Tesla', 'Erfinder', 1914014100253540772, 0x1c199421a66070afb28cb7c37de98865b28924bff26161bb65faaf5695050ee3, 0xe38ca460ca748954b29d79f0e943eed3ba85e7e13b18f69349666e31a8e3b06c9df105171796b37b4201895a2f3fe8ec8bf58a181700caaa5752a94a968c50e90ebb6280002a056126b2055ff75d69d1, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(5, 'Elfenhausen@arcor.de', 'Thomas', 'Markuk', 'Elf', 8105871797752167168, 0x98d703f0ea1def3ef9e6265a76281d125a94c80665425bd7a844580ec1a2ce98, 0x63612a1d07d78a0c945d765a10a30d9de2be602e79e3f39268d731bc6f7fa945d7d04c638000bae089ac058263f52e7c1f2c3550b35b5727e41523f2f592781add65d12b8b8c0b3226f32174cfa1bcee, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
<< "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 'Test Username', 9005874071610817324, 0xb3ee1c82a9877f664d05364106e259621b2e203bfbb5323edb7b597051efecc2, 0xa039da7d59e2475dd1aaa635f803ec1aeffc2506e7a96a934bf8d7cf4ac2a96dc962d4e1bdf8e11c5ce7e18189edc36014b89e9e72628004ec5901be6c407a955efb5142a1ee9a2f3aed888125a44aa2, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1), "
- << "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 7264393213873828644, 0x735a5c22ebe84ab1d6453991d50019b677b82b0663b023c30127ec906ee9b59a, 0xaec30051ad3ab2d2132a76e9dfe5a396d2dfbcc83a4eb27223b4da8803893959af9e29c6963f9e73eddc447cb3d3995527b94054e7fdecd7d5f8cb45c3954ff9bb2c9e0374f2124b3170301f990c5d7d, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1); ";
+ << "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 7264393213873828644, 0x735a5c22ebe84ab1d6453991d50019b677b82b0663b023c30127ec906ee9b59a, 0xaec30051ad3ab2d2132a76e9dfe5a396d2dfbcc83a4eb27223b4da8803893959af9e29c6963f9e73eddc447cb3d3995527b94054e7fdecd7d5f8cb45c3954ff9bb2c9e0374f2124b3170301f990c5d7d, '2020-02-20 16:05:47', 0, 0, 'de', 0, 1); ";
+ if (runMysql(ss.str())) {
+ return -1;
+ }
+ ss.str(std::string());
+
+ ss << "INSERT INTO `user_roles` (`id`, `user_id`, `role_id`) VALUES"
+ << "(1, 3, 1);";
+
if (runMysql(ss.str())) {
return -1;
}
diff --git a/login_server/src/cpsp/CheckTransaction.cpsp b/login_server/src/cpsp/CheckTransaction.cpsp
index 46cd5f2a3..e95629f3d 100644
--- a/login_server/src/cpsp/CheckTransaction.cpsp
+++ b/login_server/src/cpsp/CheckTransaction.cpsp
@@ -80,6 +80,7 @@ enum PageState {
//
if(transaction && transaction->getModel()->getUserId() == user_model->getID())
{
+ pt->removeTask(pending_task);
transaction->deleteFromDB();
transaction = nullptr;
}
diff --git a/package.json b/package.json
index 7909b3d78..b8d57fc0f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gradido",
- "version": "1.1.0",
+ "version": "1.1.1",
"description": "Gradido",
"main": "index.js",
"repository": "git@github.com:gradido/gradido.git",