Merge branch 'master' into paginate-user-table

This commit is contained in:
Moriz Wahl 2022-01-18 12:54:59 +01:00
commit 2e25c280cf
49 changed files with 562 additions and 288 deletions

4
.gitignore vendored
View File

@ -8,4 +8,6 @@ package-lock.json
/deployment/bare_metal/.env
/deployment/bare_metal/nginx/sites-available/gradido.conf
/deployment/bare_metal/nginx/sites-available/update-page.conf
/deployment/bare_metal/nginx/update-page/updating.html
/deployment/bare_metal/nginx/update-page/updating.html
/deployment/bare_metal/log
/deployment/bare_metal/backup

View File

@ -1,4 +1,4 @@
GRAPHQL_URI=http://localhost:4000/graphql
WALLET_AUTH_URL=http://localhost/authenticate?token=$1
WALLET_AUTH_URL=http://localhost/authenticate?token={token}
WALLET_URL=http://localhost/login
DEBUG_DISABLE_AUTH=false

4
admin/.env.template Normal file
View File

@ -0,0 +1,4 @@
GRAPHQL_URI=$GRAPHQL_URI
WALLET_AUTH_URL=$WALLET_AUTH_URL
WALLET_URL=$WALLET_URL
DEBUG_DISABLE_AUTH=false

View File

@ -38,7 +38,7 @@ export default {
this.$store.dispatch('logout')
},
wallet() {
window.location = CONFIG.WALLET_AUTH_URL.replace('$1', this.$store.state.token)
window.location = CONFIG.WALLET_AUTH_URL.replace('{token}', this.$store.state.token)
this.$store.dispatch('logout') // logout without redirect
},
},

View File

@ -19,7 +19,7 @@ const environment = {
const endpoints = {
GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql',
WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost/authenticate?token=$1',
WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost/authenticate?token={token}',
WALLET_URL: process.env.WALLET_URL || 'http://localhost/login',
}

View File

@ -2,7 +2,6 @@ import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost'
import VueApollo from 'vue-apollo'
import CONFIG from '../config'
import store from '../store/store'
import router from '../router/router'
import i18n from '../i18n'
const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI })
@ -18,7 +17,7 @@ const authLink = new ApolloLink((operation, forward) => {
if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') {
response.errors[0].message = i18n.t('error.session-expired')
store.dispatch('logout', null)
if (router.currentRoute.path !== '/logout') router.push('/logout')
window.location.assign(CONFIG.WALLET_URL)
return response
}
const newToken = operation.getContext().response.headers.get('token')

View File

@ -4,12 +4,10 @@ import CONFIG from '../config'
import VueApollo from 'vue-apollo'
import store from '../store/store'
import router from '../router/router'
import i18n from '../i18n'
jest.mock('vue-apollo')
jest.mock('../store/store')
jest.mock('../router/router')
jest.mock('../i18n')
jest.mock('apollo-boost', () => {
@ -59,13 +57,11 @@ describe('apolloProvider', () => {
errors: [{ message: '403.13 - Client certificate revoked' }],
}
// mock router
const routerPushMock = jest.fn()
router.push = routerPushMock
router.currentRoute = {
path: '/overview',
const windowLocationMock = jest.fn()
delete window.location
window.location = {
assign: windowLocationMock,
}
// mock context
const setContextMock = jest.fn()
const getContextMock = jest.fn(() => {
@ -128,21 +124,8 @@ describe('apolloProvider', () => {
expect(storeDispatchMock).toBeCalledWith('logout', null)
})
describe('current route is not logout', () => {
it('redirects to logout', () => {
expect(routerPushMock).toBeCalledWith('/logout')
})
})
describe('current route is logout', () => {
beforeEach(() => {
jest.clearAllMocks()
router.currentRoute.path = '/logout'
})
it('does not redirect to logout', () => {
expect(routerPushMock).not.toBeCalled()
})
it('redirects to logout', () => {
expect(windowLocationMock).toBeCalledWith('http://localhost/login')
})
})

View File

@ -19,7 +19,8 @@ DB_DATABASE=gradido_community
#RESEND_TIME=
RESEND_TIME=10
#EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/$1
#EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{code}
#EMAIL_LINK_SETPASSWORD=http://localhost/reset/{code}
#KLICKTIPP_USER=
#KLICKTIPP_PASSWORD=

34
backend/.env.template Normal file
View File

@ -0,0 +1,34 @@
PORT=4000
JWT_SECRET=$JWT_SECRET
JWT_EXPIRES_IN=10m
GRAPHIQL=false
GDT_API_URL=https://gdt.gradido.net
DB_HOST=localhost
DB_PORT=3306
DB_USER=$DB_USER
DB_PASSWORD=$DB_PASSWORD
DB_DATABASE=gradido_community
EMAIL=$EMAIL
EMAIL_USERNAME=$EMAIL_USERNAME
EMAIL_SENDER=$EMAIL_SENDER
EMAIL_PASSWORD=$EMAIL_PASSWORD
EMAIL_SMTP_URL=$EMAIL_SMTP_URL
EMAIL_SMTP_PORT=587
#RESEND_TIME=1 minute, 60 => 1hour, 1440 (60 minutes * 24 hours) => 24 hours
RESEND_TIME=10
EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION
EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD
#KLICKTIPP_USER=
#KLICKTIPP_PASSWORD=
#KLICKTIPP_APIKEY_DE=
#KLICKTIPP_APIKEY_EN=
#KLICKTIPP=true
COMMUNITY_NAME=
COMMUNITY_URL=
COMMUNITY_REGISTER_URL=
COMMUNITY_DESCRIPTION=
WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET

View File

@ -18,6 +18,7 @@
},
"dependencies": {
"@types/jest": "^27.0.2",
"apollo-log": "^1.1.0",
"apollo-server-express": "^2.25.2",
"apollo-server-testing": "^2.25.2",
"axios": "^0.21.1",

View File

@ -18,6 +18,8 @@ const database = {
DB_USER: process.env.DB_USER || 'root',
DB_PASSWORD: process.env.DB_PASSWORD || '',
DB_DATABASE: process.env.DB_DATABASE || 'gradido_community',
TYPEORM_LOGGING_RELATIVE_PATH:
process.env.TYPEORM_LOGGING_RELATIVE_PATH || '../deployment/bare_metal/log/typeorm.backend.log',
}
const klicktipp = {
@ -50,8 +52,9 @@ const email = {
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx',
EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com',
EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587',
EMAIL_LINK_VERIFICATION: process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/checkEmail/$1',
EMAIL_LINK_SETPASSWORD: process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/reset/$1',
EMAIL_LINK_VERIFICATION:
process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/checkEmail/{code}',
EMAIL_LINK_SETPASSWORD: process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/reset/{code}',
RESEND_TIME: isNaN(resendTime) ? 10 : resendTime,
}

View File

@ -170,7 +170,7 @@ describe('UserResolver', () => {
describe('account activation email', () => {
it('sends an account activation email', () => {
const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace(/\$1/g, emailOptIn)
const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace(/{code}/g, emailOptIn)
expect(sendAccountActivationEmail).toBeCalledWith({
link: activationLink,
firstName: 'Peter',

View File

@ -448,7 +448,7 @@ export class UserResolver {
const emailOptIn = await createEmailOptIn(loginUserId, queryRunner)
const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace(
/\$1/g,
/{code}/g,
emailOptIn.verificationCode.toString(),
)
const emailSent = await sendAccountActivationEmail({
@ -486,7 +486,7 @@ export class UserResolver {
const emailOptIn = await createEmailOptIn(loginUser.id, queryRunner)
const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace(
/\$1/g,
/{code}/g,
emailOptIn.verificationCode.toString(),
)
@ -523,7 +523,7 @@ export class UserResolver {
const optInCode = await getOptInCode(loginUser)
const link = CONFIG.EMAIL_LINK_SETPASSWORD.replace(
/\$1/g,
/{code}/g,
optInCode.verificationCode.toString(),
)

View File

@ -74,6 +74,7 @@ const createServer = async (context: any = serverContext): Promise<any> => {
const apollo = new ApolloServer({
schema: await schema(),
playground: CONFIG.GRAPHIQL,
introspection: CONFIG.GRAPHIQL,
context,
plugins,
})

View File

@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { ApolloLogPlugin } from 'apollo-log'
const plugins = [
{
requestDidStart() {
@ -19,6 +21,7 @@ const plugins = [
}
},
},
ApolloLogPlugin(),
]
export default plugins

View File

@ -1,4 +1,4 @@
import { createConnection, Connection } from 'typeorm'
import { createConnection, Connection, FileLogger } from 'typeorm'
import CONFIG from '../config'
import { entities } from '@entity/index'
@ -15,6 +15,10 @@ const connection = async (): Promise<Connection | null> => {
database: CONFIG.DB_DATABASE,
entities,
synchronize: false,
logging: true,
logger: new FileLogger('all', {
logPath: CONFIG.TYPEORM_LOGGING_RELATIVE_PATH,
}),
})
} catch (error) {
// eslint-disable-next-line no-console

View File

@ -35,7 +35,7 @@ import { LoginUserRepository } from '../typeorm/repository/LoginUser'
export const elopageWebhook = async (req: any, res: any): Promise<void> => {
// eslint-disable-next-line no-console
console.log('Elopage Hook received')
console.log('Elopage Hook received', req.body)
res.status(200).end() // Responding is important
const loginElopgaeBuyRepository = await getCustomRepository(LoginElopageBuysRepository)
const loginElopgaeBuy = new LoginElopageBuys()

View File

@ -2,7 +2,7 @@
# yarn lockfile v1
"@apollo/protobufjs@1.2.2":
"@apollo/protobufjs@1.2.2", "@apollo/protobufjs@^1.0.3":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.2.tgz#4bd92cd7701ccaef6d517cdb75af2755f049f87c"
integrity sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ==
@ -1273,6 +1273,24 @@ apollo-link@^1.2.14:
tslib "^1.9.3"
zen-observable-ts "^0.8.21"
apollo-log@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/apollo-log/-/apollo-log-1.1.0.tgz#e21287c917cf735b77adc06f07034f965e9b24de"
integrity sha512-TciLu+85LSqk7t7ZGKrYN5jFiCcRMLujBjrLiOQGHGgVVkvmKlwK0oELSS9kiHQIhTq23p8qVVWb08spLpQ7Jw==
dependencies:
apollo-server-plugin-base "^0.10.4"
chalk "^4.1.0"
fast-safe-stringify "^2.0.7"
loglevelnext "^4.0.1"
nanoid "^3.1.20"
apollo-reporting-protobuf@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.6.2.tgz#5572866be9b77f133916532b10e15fbaa4158304"
integrity sha512-WJTJxLM+MRHNUxt1RTl4zD0HrLdH44F2mDzMweBj1yHL0kSt8I1WwoiF/wiGVSpnG48LZrBegCaOJeuVbJTbtw==
dependencies:
"@apollo/protobufjs" "^1.0.3"
apollo-reporting-protobuf@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz#ae9d967934d3d8ed816fc85a0d8068ef45c371b9"
@ -1280,6 +1298,13 @@ apollo-reporting-protobuf@^0.8.0:
dependencies:
"@apollo/protobufjs" "1.2.2"
apollo-server-caching@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.5.3.tgz#cf42a77ad09a46290a246810075eaa029b5305e1"
integrity sha512-iMi3087iphDAI0U2iSBE9qtx9kQoMMEWr6w+LwXruBD95ek9DWyj7OeC2U/ngLjRsXM43DoBDXlu7R+uMjahrQ==
dependencies:
lru-cache "^6.0.0"
apollo-server-caching@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz#e6d1e68e3bb571cba63a61f60b434fb771c6ff39"
@ -1318,7 +1343,7 @@ apollo-server-core@^2.25.2:
subscriptions-transport-ws "^0.9.19"
uuid "^8.0.0"
apollo-server-env@^3.1.0:
apollo-server-env@^3.0.0, apollo-server-env@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-3.1.0.tgz#0733c2ef50aea596cc90cf40a53f6ea2ad402cd0"
integrity sha512-iGdZgEOAuVop3vb0F2J3+kaBVi4caMoxefHosxmgzAbbSpvWehB8Y1QiSyyMeouYC38XNVk5wnZl+jdGSsWsIQ==
@ -1354,6 +1379,13 @@ apollo-server-express@^2.25.2:
subscriptions-transport-ws "^0.9.19"
type-is "^1.6.16"
apollo-server-plugin-base@^0.10.4:
version "0.10.4"
resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.10.4.tgz#fbf73f64f95537ca9f9639dd7c535eb5eeb95dcd"
integrity sha512-HRhbyHgHFTLP0ImubQObYhSgpmVH4Rk1BinnceZmwudIVLKrqayIVOELdyext/QnSmmzg5W7vF3NLGBcVGMqDg==
dependencies:
apollo-server-types "^0.6.3"
apollo-server-plugin-base@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.13.0.tgz#3f85751a420d3c4625355b6cb3fbdd2acbe71f13"
@ -1368,6 +1400,15 @@ apollo-server-testing@^2.25.2:
dependencies:
apollo-server-core "^2.25.2"
apollo-server-types@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.6.3.tgz#f7aa25ff7157863264d01a77d7934aa6e13399e8"
integrity sha512-aVR7SlSGGY41E1f11YYz5bvwA89uGmkVUtzMiklDhZ7IgRJhysT5Dflt5IuwDxp+NdQkIhVCErUXakopocFLAg==
dependencies:
apollo-reporting-protobuf "^0.6.2"
apollo-server-caching "^0.5.3"
apollo-server-env "^3.0.0"
apollo-server-types@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.9.0.tgz#ccf550b33b07c48c72f104fbe2876232b404848b"
@ -2559,6 +2600,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fast-safe-stringify@^2.0.7:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
fastq@^1.6.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
@ -4008,6 +4054,11 @@ loglevel@^1.6.7:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
loglevelnext@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-4.0.1.tgz#4406c6348c243a35272ac75d7d8e4e60ecbcd011"
integrity sha512-/tlMUn5wqgzg9msy0PiWc+8fpVXEuYPq49c2RGyw2NAh0hSrgq6j/Z3YPnwWsILMoFJ+ZT6ePHnWUonkjDnq2Q==
long@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
@ -4194,6 +4245,11 @@ named-placeholders@^1.1.2:
dependencies:
lru-cache "^4.1.3"
nanoid@^3.1.20:
version "3.1.32"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.32.tgz#8f96069e6239cc0a9ae8c0d3b41a3b4933a88c0a"
integrity sha512-F8mf7R3iT9bvThBoW4tGXhXFHCctyCiUUPrWF8WaTqa3h96d9QybkSeba43XVOOE3oiLfkVDe4bT8MeGmkrTxw==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"

8
database/.env.template Normal file
View File

@ -0,0 +1,8 @@
DB_HOST=localhost
DB_PORT=3306
DB_USER=$DB_USER
DB_PASSWORD=$DB_PASSWORD
DB_DATABASE=gradido_community
MIGRATIONS_TABLE=migrations
TYPEORM_SEEDING_FACTORIES=src/factories/**/*{.ts,.js}

View File

@ -1,14 +1,37 @@
NGINX_SERVER_NAME=_
GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log
#Example data
# start script
DEPLOY_SEED_DATA=false
#DEPLOY_SEED_DATA=true
#
#NGINX_REWRITE_LEGACY_URLS=true
#NGINX_SSL=true
#NGINX_SERVER_NAME=stage1.gradido.net
#NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem
#NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem
#NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem
#NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf
#NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page
# nginx
NGINX_REWRITE_LEGACY_URLS=true
NGINX_SSL=true
NGINX_SERVER_NAME=stage1.gradido.net
NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem
NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem
NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem
NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf
NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page
# webhook
WEBHOOK_GITHUB_SECRET=secret
WEBHOOK_GITHUB_BRANCH=master
# backend
EMAIL=true
EMAIL_USERNAME=peter@lustig.de
EMAIL_SENDER=peter@lustig.de
EMAIL_PASSWORD=1234
EMAIL_SMTP_URL=smtp.lustig.de
EMAIL_LINK_VERIFICATION=https://stage1.gradido.net/checkEmail/{code}
EMAIL_LINK_SETPASSWORD=https://stage1.gradido.net/reset/{code}
WEBHOOK_ELOPAGE_SECRET=secret
# frontend
GRAPHQL_URI=https://stage1.gradido.net/graphql
ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token}
# admin
WALLET_AUTH_URL=https://stage1.gradido.net/authenticate?token={token}
WALLET_URL=https://stage1.gradido.net/login

28
deployment/bare_metal/backup.sh Executable file
View File

@ -0,0 +1,28 @@
#!/bin/bash
# This script will shut down all services, backup the whole database and restart the services
# Find current directory & configure paths
set -o allexport
SCRIPT_PATH=$(realpath $0)
SCRIPT_DIR=$(dirname $SCRIPT_PATH)
PROJECT_ROOT=$SCRIPT_DIR/../..
set +o allexport
# Load backend .env for DB_USERNAME, DB_PASSWORD & DB_DATABASE
# NOTE: all config values will be in process.env when starting
# the services and will therefore take precedence over the .env
if [ -f "$PROJECT_ROOT/backend/.env" ]; then
export $(cat $PROJECT_ROOT/backend/.env | sed 's/#.*//g' | xargs)
else
export $(cat $PROJECT_ROOT/backend/.env.dist | sed 's/#.*//g' | xargs)
fi
# Stop Services
pm2 stop gradido-backend
# Backup data
mysqldump --databases --single-transaction --quick --lock-tables=false > ${SCRIPT_DIR}/backup/mariadb-backup-$(date +%d-%m-%Y_%H-%M-%S).sql -u ${DB_USER} -p${DB_PASSWORD} ${DB_DATABASE}
# Start Services
pm2 start gradido-backend

View File

View File

@ -3,15 +3,25 @@
# This install script requires the minimum requirements already installed.
# How to do this is described in detail in [setup.md](./setup.md)
# Load .env or .env.dist if not present
# Find current directory & configure paths
set -o allexport
if [ -f ".env" ]; then
source .env
else
source .env.dist
fi
SCRIPT_PATH=$(realpath $0)
SCRIPT_DIR=$(dirname $SCRIPT_PATH)
PROJECT_ROOT=$SCRIPT_DIR/../..
set +o allexport
# Load .env or .env.dist if not present
# NOTE: all config values will be in process.env when starting
# the services and will therefore take precedence over the .env
if [ -f "$SCRIPT_DIR/.env" ]; then
export $(cat $SCRIPT_DIR/.env | sed 's/#.*//g' | xargs)
else
export $(cat $SCRIPT_DIR/.env.dist | sed 's/#.*//g' | xargs)
fi
# Configure git
git config pull.ff only
# Install mariadb
sudo apt-get install -y mariadb-server
sudo mysql_secure_installation
@ -23,57 +33,26 @@ sudo mysql_secure_installation
# Remove test database and access to it? [Y/n] Y
# Reload privilege tables now? [Y/n] Y
# create db user
DB_USER=gradido
DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo);
# create table
#create database gradido_community
# DEFAULT CHARACTER SET utf8mb4
# DEFAULT COLLATE utf8mb4_unicode_ci;
# GRANT ALL PRIVILEGES ON gradido_community.* TO '$DB_USER'@'localhost';
sudo mysql <<EOFMYSQL
CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWD';
GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
EOFMYSQL
# TODO generate .env
echo $DB_PASSWORD
#TODO go to database
#TODO generate this
#TODO database setup
cp .env.dist .env
#TODO go to backend
#TODO generate this
#TODO database setup
#TODOchange jwt secret
#TODO change email releated stuff
cp .env.dist .env
#TODO go to frontend
#TODO generate this
#TODO backend url
#TODO admin url
cp .env.dist .env
#TODO go to admin
#TODO generate this
#TODO change graphqlurl
#TODO change wallet url
cp .env.dist .env
#TODO import old database
# Install nginx
sudo apt-get install -y nginx
sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /home/gradido/gradido/deployment/bare_metal/nginx/sites-available/gradido.conf /etc/nginx/sites-available
sudo ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled
# sudo ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled
sudo ln -s /home/gradido/gradido/deployment/bare_metal/nginx/sites-available/update-page.conf /etc/nginx/sites-available
cd /etc/nginx
sudo ln -s /home/gradido/gradido/deployment/bare_metal/nginx/common common
sudo ln -s /home/gradido/gradido/deployment/bare_metal/nginx/common /etc/nginx/
sudo rmdir /etc/nginx/conf.d
sudo ln -s /home/gradido/gradido/deployment/bare_metal/nginx/conf.d /etc/nginx/
# Allow nginx configuration and restart for gradido
#TODO generate file
sudo nano /etc/sudoers.d/gradido
> gradido ALL=(ALL) NOPASSWD: /etc/init.d/nginx start,/etc/init.d/nginx stop,/etc/init.d/nginx restart
sudo chmod a+rw /etc/nginx/sites-enabled
# Install node 16.x
curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y build-essential
# Install yarn
sudo apt-get install -y curl
@ -83,73 +62,64 @@ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/source
sudo apt-get update
sudo apt-get install -y yarn
# Install node 16.x
curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y build-essential
# Install pm2
sudo yarn global add pm2
pm2 startup
> execute command output in shell
# Install certbot
sudo apt-get install -y certbot
sudo apt-get install -y python3-certbot-nginx
sudo certbot --certonly
sudo certbot
> Enter email address (used for urgent renewal and security notices) > support@gradido.net
> Please read the Terms of Service at > Y
> Would you be willing, once your first certificate is successfully issued, to > N
> No names were found in your configuration files. Please enter in your domain > stage1.gradido.net
git config pull.ff only
# Install logrotate
# sudo apt-get install -y logrotate
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/logrotate/gradido.conf.template > $SCRIPT_DIR/logrotate/gradido.conf
sudo mv $SCRIPT_DIR/logrotate/gradido.conf /etc/logrotate.d/gradido.conf
sudo chown root:root /etc/logrotate.d/gradido.conf
# Allow nginx configuration and restart for gradido
sudo nano /etc/sudoers.d/gradido
> gradido ALL=(ALL) NOPASSWD: /etc/init.d/nginx start,/etc/init.d/nginx stop,/etc/init.d/nginx restart
sudo chmod a+rw /etc/nginx/sites-enabled
# Install mysql autobackup
sudo apt-get install -y automysqlbackup
# Webhooks (optional)
sudo apt install webhook
nano ~/hooks.json
```
[
{
"id": "github",
"execute-command": "/home/gradido/gradido/deployment/bare_metal/start.sh",
"pass-arguments-to-command": [
{
"source": "string",
"name": "new_deployment"
},
],
"command-working-directory": "/home/gradido/gradido/deployment/bare_metal",
"trigger-rule": {
"and": [
{
"match": {
"type": "payload-hash-sha1",
"secret": "secret",
"parameter": {
"source": "header",
"name": "X-Hub-Signature"
}
}
},
{
"match": {
"type": "value",
"value": "refs/heads/new_deployment",
"parameter": {
"source": "payload",
"name": "ref"
}
}
}
]
}
}
]
```
# Webhooks (optional) (for development)
sudo apt install -y webhook
# TODO generate
# put hook into github
# TODO adjust secret
# TODO adjust branch if needed
# https://stage1.gradido.net/hooks/github
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/webhook/hooks.json.template > ~/hooks.json
webhook -hooks ~/hooks.json &
# or for debugging
webhook -hooks ~/hooks.json -verbose
# webhook -hooks ~/hooks.json -verbose
# create db user
export DB_USER=gradido
export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo);
sudo mysql <<EOFMYSQL
CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
EOFMYSQL
# Configure database
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env
# Configure backend
export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo);
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env
# Configure frontend
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env
# Configure admin
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
# Start gradido
# Note: on first startup some errors will occur - nothing serious
./start.sh

View File

View File

@ -0,0 +1,7 @@
$GRADIDO_LOG_PATH/* {
weekly
rotate 26
size 10M
compress
delaycompress
}

View File

@ -0,0 +1,4 @@
log_format gradido_log '$remote_addr - $remote_user [$time_local] '
'"$request_method $status $request_uri"'
' "$http_referer" "$http_user_agent"'
' $server_protocol $body_bytes_sent $request_time';

View File

@ -21,9 +21,18 @@ server {
include /etc/nginx/common/protect.conf;
include /etc/nginx/common/protect_add_header.conf;
#include /etc/nginx/common/ssl.conf;
#gzip_static on;
gzip on;
gzip_proxied any;
gzip_types
text/css
text/javascript
text/xml
text/plain
application/javascript
application/x-javascript
application/json;
# Legacy URLS
set $REWRITE_LEGACY_URLS "$NGINX_REWRITE_LEGACY_URLS";
@ -42,6 +51,9 @@ server {
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
}
# Backend
@ -55,6 +67,9 @@ server {
proxy_pass http://127.0.0.1:4000;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.backend.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.backend.log warn;
}
# Backend webhooks
@ -68,11 +83,17 @@ server {
proxy_pass http://127.0.0.1:4000/hook;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.backend.hook.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.backend.hook.log warn;
}
# Webhook reverse proxy
location /hooks/ {
proxy_pass http://127.0.0.1:9000/hooks/;
access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.hooks.log warn;
}
# Admin Frontend
@ -86,6 +107,9 @@ server {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.admin.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
}
# TODO this could be a performance optimization
@ -98,6 +122,4 @@ server {
# }
# try_files $uri $uri/ /index.html = 404;
#}
#access_log /var/log/nginx/access.log main;
}

View File

@ -6,9 +6,18 @@ server {
include /etc/nginx/common/protect.conf;
include /etc/nginx/common/protect_add_header.conf;
#include /etc/nginx/common/ssl.conf;
#gzip_static on;
gzip on;
gzip_proxied any;
gzip_types
text/css
text/javascript
text/xml
text/plain
application/javascript
application/x-javascript
application/json;
# Legacy URLS
set $REWRITE_LEGACY_URLS "$NGINX_REWRITE_LEGACY_URLS";
@ -27,6 +36,9 @@ server {
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
}
# Backend
@ -40,6 +52,9 @@ server {
proxy_pass http://127.0.0.1:4000;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.backend.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.backend.log warn;
}
# Backend webhooks
@ -54,11 +69,17 @@ server {
# no trailing slash to keep the hook/ prefix
proxy_pass http://127.0.0.1:4000/hook;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.backend.hook.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.backend.hook.log warn;
}
# Webhook reverse proxy
location /hooks/ {
proxy_pass http://127.0.0.1:9000/hooks/;
access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.hooks.log warn;
}
# Admin Frontend
@ -72,6 +93,9 @@ server {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.admin.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
}
# TODO this could be a performance optimization
@ -84,6 +108,4 @@ server {
# }
# try_files $uri $uri/ /index.html = 404;
#}
#access_log /var/log/nginx/access.log main;
}

View File

@ -22,15 +22,16 @@ server {
include /etc/nginx/common/protect.conf;
include /etc/nginx/common/protect_add_header.conf;
gzip on;
root $NGINX_UPDATE_PAGE_ROOT;
index updating.html;
#location / {
# alias $NGINX_UPDATE_PAGE_ROOT;
# index updating.html;
#}
#access_log /var/log/nginx/access.log main;
location / {
try_files /updating.html =404;
}
access_log $GRADIDO_LOG_PATH/nginx-access.update-page.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.update-page.log warn;
}

View File

@ -1,21 +1,22 @@
server {
server_name _;
listen 80;
listen [::]:80;
server_name _;
listen 80;
listen [::]:80;
include /etc/nginx/common/protect.conf;
include /etc/nginx/common/protect_add_header.conf;
include /etc/nginx/common/protect.conf;
include /etc/nginx/common/protect_add_header.conf;
root $NGINX_UPDATE_PAGE_ROOT;
index updating.html;
gzip on;
#location / {
# alias $NGINX_UPDATE_PAGE_ROOT;
# index updating.html;
#}
root $NGINX_UPDATE_PAGE_ROOT;
index updating.html;
access_log /var/log/nginx/access.log main;
location / {
try_files /updating.html =404;
}
access_log $GRADIDO_LOG_PATH/nginx-access.update-page.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.update-page.log warn;
}

View File

@ -1,71 +1,3 @@
# nginx security
sudo cat << "EOF" > ssl.conf
##
# SSL Settings
##
# disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
# enables server-side protection from BEAST attacks
# http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html
ssl_prefer_server_ciphers on;
# enable session resumption to improve https performance
# http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# ciphers chosen for forward secrecy and compatibility
# http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
# enable ocsp stapling (mechanism by which a site can convey certificate revocation information to visitors in a privacy-preserving, scalable manner)
# http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/
resolver 8.8.8.8 8.8.4.4;
ssl_stapling on;
ssl_stapling_verify on;
# ssl_trusted_certificate /etc/nginx/ssl/star_forgott_com.crt;
# config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
# also https://hstspreload.org/
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
EOF
cd /etc/nginx/conf.d
sudo cat <<EOF > logging.conf
log_format main '$http_x_forwarded_for - $remote_user [$time_local] '
'"$request_method $scheme://$host$request_uri $server_protocol" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
EOF
# fail2ban enable blocking to many http request resulting in forbidden
echo "fail2ban config"
cd /etc/fail2ban/filter.d
sudo cat <<EOF > nginx-forbidden.conf
[Definition]
failregex = ^.*\[error\] \d+#\d+: .* forbidden .*, client: <HOST>, .*$
ignoreregex =
EOF
cd /etc/fail2ban/jail.d
sudo cat <<EOF > nginx-forbidden.conf
[nginx-forbidden]
enabled = true
filter = nginx-forbidden
port = http,https
logpath = /var/log/nginx/*error*.log
findtime = 60
bantime = 6000
maxretry = 3
EOF
sudo service fail2ban restart
# phpmyadmin
echo "install and secure phpmyadmin"
sudo apt install phpmyadmin

View File

@ -0,0 +1,42 @@
#!/bin/bash
# This script will shut down all services, replace the whole database with the selected backup and restart the services
# Find current directory & configure paths
set -o allexport
SCRIPT_PATH=$(realpath $0)
SCRIPT_DIR=$(dirname $SCRIPT_PATH)
PROJECT_ROOT=$SCRIPT_DIR/../..
set +o allexport
# Parameter is a proper file?
export BACKUP_FILE=${SCRIPT_DIR}/backup/$1
if [ ! -f "$BACKUP_FILE" ]; then
return "File '$BACKUP_FILE' does not exist" 2>/dev/null || exit 1
fi
# Load backend .env for DB_USERNAME, DB_PASSWORD & DB_DATABASE
# NOTE: all config values will be in process.env when starting
# the services and will therefore take precedence over the .env
if [ -f "$PROJECT_ROOT/backend/.env" ]; then
export $(cat $PROJECT_ROOT/backend/.env | sed 's/#.*//g' | xargs)
else
export $(cat $PROJECT_ROOT/backend/.env.dist | sed 's/#.*//g' | xargs)
fi
# Stop gradido-backend service
pm2 stop gradido-backend
# Backup data
mysqldump --databases --single-transaction --quick --lock-tables=false > ${SCRIPT_DIR}/backup/mariadb-restore-backup-$(date +%d-%m-%Y_%H-%M-%S).sql -u ${DB_USER} -p${DB_PASSWORD} ${DB_DATABASE}
# Restore Data
mysql -u ${DB_USER} -p${DB_PASSWORD} <<EOFMYSQL
source $BACKUP_FILE
EOFMYSQL
# Update database if needed (use dev_up for seeding setups)
yarn --cwd $PROJECT_ROOT/database up
# Start gradido-backend service
pm2 start gradido-backend

View File

@ -4,12 +4,12 @@
> ssh root@gddhost.tld
# change default shell
chsh
# change root default shell
> chsh -s /bin/bash
# Create user `gradido`
> useradd -d /home/gradido -m gradido
> passwd gradido
>> enter new
>> enter new password twice
# Gives the user priviledges - this might be omitted in order to harden security
# Care: This will require another administering user if you don't want root access.
@ -18,6 +18,8 @@ chsh
# You might lock yourself out, if done wrong.
> usermod -a -G sudo gradido
# change gradido default shell
> chsh -s /bin/bash gradido
# Install sudo
> apt-get install sudo
# switch to the new user
@ -67,11 +69,19 @@ chsh
> sudo ufw enable
## fail2ban
> sudo apt-get install fail2ban
> sudo apt-get install -y fail2ban
> sudo /etc/init.d/fail2ban restart
# Install gradido
> sudo apt-get install git
> git clone https://github.com/gradido/gradido.git
> cd gradido/deployment/bare_metal
# Adjust .env
# NOTE ';' can not be part of any value
> cd gradido/deployment/bare_metal
> cp .env.dist .env
> nano .env
>> Adjust values accordingly
# TODO the install.sh is not yet ready to run directly - consider to use it as pattern to do it manually
> ./install.sh

View File

@ -11,18 +11,18 @@ NGINX_CONFIG_DIR=$SCRIPT_DIR/nginx/sites-available
set +o allexport
# Load .env or .env.dist if not present
set -o allexport
#TODO
# NOTE: all config values will be in process.env when starting
# the services and will therefore take precedence over the .env
if [ -f "$SCRIPT_DIR/.env" ]; then
source $SCRIPT_DIR/.env
export $(cat $SCRIPT_DIR/.env | sed 's/#.*//g' | xargs)
else
source $SCRIPT_DIR/.env.dist
export $(cat $SCRIPT_DIR/.env.dist | sed 's/#.*//g' | xargs)
fi
set +o allexport
# lock start
if [ -f $LOCK_FILE ] ; then
return "Already building!" 2>/dev/null || exit 1
echo "Already building!"
exit 1
fi
touch $LOCK_FILE
@ -80,28 +80,40 @@ fi
# Install & build backend
echo 'Updating backend<br>' >> $UPDATE_HTML
cd $PROJECT_ROOT/backend
# TODO maybe handle this differently?
unset NODE_ENV
yarn install
yarn build
# TODO maybe handle this differently?
export NODE_ENV=production
pm2 delete gradido-backend
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start"
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.log --log-date-format 'DD-MM HH:mm:ss.SSS'
pm2 save
# Install & build frontend
echo 'Updating frontend<br>' >> $UPDATE_HTML
cd $PROJECT_ROOT/frontend
# TODO maybe handle this differently?
unset NODE_ENV
yarn install
yarn build
# TODO maybe handle this differently?
export NODE_ENV=production
pm2 delete gradido-frontend
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start"
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.log --log-date-format 'DD-MM HH:mm:ss.SSS'
pm2 save
# Install & build admin
echo 'Updating admin<br>' >> $UPDATE_HTML
cd $PROJECT_ROOT/admin
# TODO maybe handle this differently?
unset NODE_ENV
yarn install
yarn build
# TODO maybe handle this differently?
export NODE_ENV=production
pm2 delete gradido-admin
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start"
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.log --log-date-format 'DD-MM HH:mm:ss.SSS'
pm2 save
# let nginx showing gradido

View File

@ -0,0 +1,37 @@
[
{
"id": "github",
"execute-command": "/home/gradido/gradido/deployment/bare_metal/start.sh",
"pass-arguments-to-command": [
{
"source": "string",
"name": "$WEBHOOK_GITHUB_BRANCH"
}
],
"command-working-directory": "/home/gradido/gradido/deployment/bare_metal",
"trigger-rule": {
"and": [
{
"match": {
"type": "payload-hash-sha1",
"secret": "$WEBHOOK_GITHUB_SECRET",
"parameter": {
"source": "header",
"name": "X-Hub-Signature"
}
}
},
{
"match": {
"type": "value",
"value": "refs/heads/$WEBHOOK_GITHUB_BRANCH",
"parameter": {
"source": "payload",
"name": "ref"
}
}
}
]
}
}
]

View File

@ -1,4 +1,3 @@
GRAPHQL_URI=http://localhost:4000/graphql
GRAPHQL_URI=http://localhost/graphql
DEFAULT_PUBLISHER_ID=2896
#BUILD_COMMIT=0000000
ADMIN_AUTH_URL=http://localhost/admin/authenticate?token=$1
ADMIN_AUTH_URL=http://localhost/admin/authenticate?token={token}

3
frontend/.env.template Normal file
View File

@ -0,0 +1,3 @@
GRAPHQL_URI=$GRAPHQL_URI
DEFAULT_PUBLISHER_ID=2896
ADMIN_AUTH_URL=$ADMIN_AUTH_URL

View File

@ -38,14 +38,19 @@
</b-link>
</div>
<b-nav-item to="/overview" class="mb-3">
<b-icon icon="house" aria-hidden="true"></b-icon>
{{ $t('overview') }}
</b-nav-item>
<b-nav-item to="/send" class="mb-3">{{ $t('send') }}</b-nav-item>
<b-nav-item to="/send" class="mb-3">
<b-icon icon="arrow-left-right" aria-hidden="true"></b-icon>
{{ $t('send') }}
</b-nav-item>
<b-nav-item to="/transactions" class="mb-3">
<b-icon icon="layout-text-sidebar-reverse" aria-hidden="true"></b-icon>
{{ $t('transactions') }}
</b-nav-item>
<b-nav-item to="/profile" class="mb-3">
<b-icon icon="gear-fill" aria-hidden="true"></b-icon>
<b-icon icon="gear" aria-hidden="true"></b-icon>
{{ $t('site.navbar.my-profil') }}
</b-nav-item>
<br />
@ -55,7 +60,7 @@
<b-badge v-if="!$store.state.hasElopage" pill variant="danger">!</b-badge>
</b-nav-item>
<b-nav-item class="mb-3" v-if="$store.state.isAdmin" @click="$emit('admin')">
<b-icon icon="link45deg" aria-hidden="true"></b-icon>
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
{{ $t('admin_area') }}
</b-nav-item>
<b-nav-item class="mb-3" @click="$emit('logout')">

View File

@ -4,11 +4,20 @@
<p></p>
<div class="mb-6">
<b-nav vertical class="w-200">
<b-nav-item to="/overview" class="mb-3" active>{{ $t('overview') }}</b-nav-item>
<b-nav-item to="/send" class="mb-3">{{ $t('send') }}</b-nav-item>
<b-nav-item to="/transactions" class="mb-3">{{ $t('transactions') }}</b-nav-item>
<b-nav-item to="/overview" class="mb-3" active>
<b-icon icon="house" aria-hidden="true"></b-icon>
{{ $t('overview') }}
</b-nav-item>
<b-nav-item to="/send" class="mb-3">
<b-icon icon="arrow-left-right" aria-hidden="true"></b-icon>
{{ $t('send') }}
</b-nav-item>
<b-nav-item to="/transactions" class="mb-3">
<b-icon icon="layout-text-sidebar-reverse" aria-hidden="true"></b-icon>
{{ $t('transactions') }}
</b-nav-item>
<b-nav-item to="/profile" class="mb-3">
<b-icon icon="gear-fill" aria-hidden="true"></b-icon>
<b-icon icon="gear" aria-hidden="true"></b-icon>
{{ $t('site.navbar.my-profil') }}
</b-nav-item>
</b-nav>
@ -20,7 +29,7 @@
<b-badge v-if="!$store.state.hasElopage" pill variant="danger">!</b-badge>
</b-nav-item>
<b-nav-item class="mb-3" v-if="$store.state.isAdmin" @click="$emit('admin')">
<b-icon icon="link45deg" aria-hidden="true"></b-icon>
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
{{ $t('admin_area') }}
</b-nav-item>
<b-nav-item class="mb-3" @click="$emit('logout')">

View File

@ -19,8 +19,8 @@ const environment = {
}
const endpoints = {
GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql',
ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token=$1',
GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost/graphql',
ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token={token}',
}
const options = {}

View File

@ -100,6 +100,7 @@ export default {
})
.catch((error) => {
this.pending = true
this.transactionCount = -1
this.$toasted.global.error(error.message)
// what to do when loading balance fails?
})
@ -108,7 +109,7 @@ export default {
this.balance -= ammount
},
admin() {
window.location.assign(CONFIG.ADMIN_AUTH_URL.replace('$1', this.$store.state.token))
window.location.assign(CONFIG.ADMIN_AUTH_URL.replace('{token}', this.$store.state.token))
this.$store.dispatch('logout') // logout without redirect
},
setVisible(bool) {

View File

@ -1,6 +1,6 @@
<template>
<div>
<div>
<div class="container-fluid">
<b-row>
<b-col class="col-6">
<b-row>

View File

@ -56,16 +56,20 @@ describe('GddTransactionList', () => {
})
})
it('Transactions Array is empty, 0 transactions', () => {
expect(wrapper.find('div.test-empty-transactionlist').text()).toContain(
'error.empty-transactionlist',
)
expect(wrapper.find('div.test-empty-transactionlist').exists()).toBe(false)
})
})
describe('without any properties', () => {
beforeEach(async () => {
await wrapper.setProps({
transactions: [],
transactionCount: -1,
})
})
it('renders text saying that there are error.empty-transactionlist ', () => {
expect(wrapper.find('div.gdd-transaction-list').text()).toContain(
'error.empty-transactionlist',
'transaction.nullTransactions',
)
})
it('renders text saying that there are no transaction.nullTransactions', () => {

View File

@ -7,7 +7,7 @@
{{ $t('error.no-transactionlist') }}
</small>
</div>
<div v-if="!transactionCount" class="test-empty-transactionlist text-right">
<div v-if="transactionCount < 0" class="test-empty-transactionlist text-right">
<b-icon icon="exclamation-triangle" class="mr-2" style="color: red"></b-icon>
<small>{{ $t('error.empty-transactionlist') }}</small>
</div>
@ -134,7 +134,7 @@
:per-page="pageSize"
:total-rows="transactionCount"
></pagination-buttons>
<div v-if="transactionCount === 0" class="mt-4 text-center">
<div v-if="transactionCount < 0" class="mt-4 text-center">
<span>{{ $t('transaction.nullTransactions') }}</span>
</div>
</div>

View File

@ -3,7 +3,10 @@
<div>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a @click="showUserData ? (showUserData = !showUserData) : cancelEdit()">
<a
class="cursor-pointer"
@click="showUserData ? (showUserData = !showUserData) : cancelEdit()"
>
<span class="pointer mr-3">{{ $t('settings.name.change-name') }}</span>
<b-icon v-if="showUserData" class="pointer ml-3" icon="pencil"></b-icon>
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
@ -130,4 +133,8 @@ export default {
},
}
</script>
<style></style>
<style>
.cursor-pointer {
cursor: pointer;
}
</style>

View File

@ -3,7 +3,10 @@
<div>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a @click="showPassword ? (showPassword = !showPassword) : cancelEdit()">
<a
class="cursor-pointer"
@click="showPassword ? (showPassword = !showPassword) : cancelEdit()"
>
<span class="pointer mr-3">{{ $t('settings.password.change-password') }}</span>
<b-icon v-if="showPassword" class="pointer ml-3" icon="pencil"></b-icon>
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
@ -91,3 +94,8 @@ export default {
},
}
</script>
<style>
.cursor-pointer {
cursor: pointer;
}
</style>

View File

@ -3,7 +3,10 @@
<div>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a @click="showLanguage ? (showLanguage = !showLanguage) : cancelEdit()">
<a
class="cursor-pointer"
@click="showLanguage ? (showLanguage = !showLanguage) : cancelEdit()"
>
<span class="pointer mr-3">{{ $t('settings.language.changeLanguage') }}</span>
<b-icon v-if="showLanguage" class="pointer ml-3" icon="pencil"></b-icon>
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
@ -110,3 +113,8 @@ export default {
},
}
</script>
<style>
.cursor-pointer {
cursor: pointer;
}
</style>

View File

@ -88,4 +88,22 @@ describe('Thx', () => {
expect(wrapper.find('a.btn').attributes('href')).toBe('/overview')
})
})
describe('coming from /login', () => {
beforeEach(() => {
wrapper = Wrapper(createMockObject('login'))
})
it('renders the thanks text', () => {
expect(wrapper.find('p.h4').text()).toBe('site.thx.activateEmail')
})
it('renders the thanks redirect button', () => {
expect(wrapper.find('a.btn').text()).toBe('login')
})
it('links the redirect button to /login', () => {
expect(wrapper.find('a.btn').attributes('href')).toBe('/login')
})
})
})

View File

@ -45,6 +45,8 @@ const textFields = {
login: {
headline: 'site.thx.errorTitle',
subtitle: 'site.thx.activateEmail',
button: 'login',
linkTo: '/login',
},
}