Merge branch 'tibor' into 'master'

Tibor

See merge request bossanyit/aitrainer_server!1
This commit is contained in:
Bossányi Tibor 2020-06-10 14:31:49 +00:00
commit 6b558a0173
71 changed files with 3460 additions and 0 deletions

32
.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/

66
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,66 @@
stages:
- build
- prepare
- test
- deploy
variables:
# Configure mysql environment variables (https://hub.docker.com/_/mysql/)
MYSQL_DATABASE: "aitrainer"
MYSQL_ROOT_PASSWORD: "andio2009"
MYSQL_USER: "aitrainer"
MYSQL_PASSWORD: "andio2009"
before_script:
- echo `pwd` # debug
- echo "$CI_BUILD_NAME, $CI_BUILD_REF_NAME $CI_BUILD_STAGE" # debug
- export GRADLE_USER_HOME=`pwd`/.gradle
cache:
paths:
- .gradle/wrapper
- .gradle/caches
build:
stage: build
image: openjdk:latest
script:
- ./gradlew assemble
artifacts:
paths:
- build/libs/*.jar
expire_in: 1 week
only:
- master
connect:
stage: prepare
image: mysql:latest
script:
- apt-get update && apt-get --assume-yes install mysql-client
- mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql -e "use $MYSQL_DATABASE; show tables;"
- mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql -e "use $MYSQL_DATABASE; DROP table if exists customer; DROP table if exists exercises; DROP table if exists exercise_type; DROP table if exists exercise_ages;"
- mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql < "data/db/install.sql" #first time
test:
stage: test
image: openjdk:latest
script:
- export spring_profiles_active=test
- ./gradlew check
deploy:
stage: deploy
image: mysql:latest
script:
- apt-get update && apt-get --assume-yes install sshpass
- chmod +x ci-cd/deploy.sh
- ci-cd/deploy.sh
only:
- master
after_script:
- echo "End CI"

1
.gitlab-runner-register Normal file
View File

@ -0,0 +1 @@
docker run --rm -t -i -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register

58
build.gradle.kts Normal file
View File

@ -0,0 +1,58 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.3.0.RELEASE"
id("io.spring.dependency-management") version "1.0.9.RELEASE"
kotlin("jvm") version "1.3.72"
kotlin("plugin.spring") version "1.3.72"
kotlin("plugin.jpa") version "1.3.72"
kotlin("plugin.serialization") version "1.3.70"
}
group = "com.aitrainer"
version = "0.0.5"
java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-aop")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.3.0.RELEASE")
implementation("org.springframework.security.oauth:spring-security-oauth2:2.5.0.RELEASE")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.apache.logging.log4j:log4j-core:2.13.3")
implementation("org.apache.logging.log4j:log4j-api:2.13.3")
implementation("org.slf4j:slf4j-api:1.7.30")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0") // JVM dependency
implementation("io.jsonwebtoken:jjwt:0.9.1")
runtimeOnly("mysql:mysql-connector-java")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
testImplementation("junit:junit:4.13")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:1.3.72")
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
}
}

1
ci-cd/.ssh/.scp Normal file
View File

@ -0,0 +1 @@
tbi6012AndiBossanyi

52
ci-cd/config.toml Normal file
View File

@ -0,0 +1,52 @@
concurrent = 4
log_level = "warning"
[session_server]
listen_address = "0.0.0.0:8093" # listen on all available interfaces on port 8093
advertise_address = "andio.club:8093"
session_timeout = 1800
[[runners]]
name = "aitraner-server-docker"
url = "https://andio.club"
token = "R_-WrxvRXkP6HuU95dEs"
limit = 0
executor = "shell"
builds_dir = "/home/bosi/build"
shell = "bash"
environment = ["ENV=value", "LC_ALL=en_US.UTF-8"]
clone_url = "http://localhost"
[runners.docker]
host = ""
hostname = ""
tls_cert_path = ""
image = "docker-runner"
memory = "128m"
memory_swap = "256m"
memory_reservation = "64m"
oom_kill_disable = false
cpuset_cpus = "0,1"
cpus = "2"
dns = ["8.8.8.8"]
dns_search = [""]
privileged = false
userns_mode = "host"
cap_add = ["NET_ADMIN"]
cap_drop = ["DAC_OVERRIDE"]
devices = ["/dev/net/tun"]
disable_cache = false
wait_for_services_timeout = 30
cache_dir = ""
volumes = ["/data", "/home/project/cache"]
extra_hosts = ["127.0.0.1"]
shm_size = 300000
volumes_from = ["storage_container:ro"]
links = ["mysql_container:mysql"]
allowed_images = ["ruby:*", "python:*", "php:*"]
allowed_services = ["mysql"]
[[runners.docker.services]]
name = "mysql"
alias = "db"
[runners.docker.sysctls]
"net.ipv4.ip_forward" = "1"

1
ci-cd/deploy.sh Normal file
View File

@ -0,0 +1 @@
sshpass -f /ci-cd/.ssh/.scp scp -p 6622 build/libs/aitrainer_server-0.0.2.jar bosi@andio.shop:/home/bosi/aitrainer/deploy/aitrainer_server.jar

View File

@ -0,0 +1,98 @@
version: '3.8'
services:
jira:
image: 'atlassian/jira-software:latest'
container_name: 'jira'
restart: 'always'
environment:
ATL_TOMCAT_PORT: 8082
ATL_TOMCAT_SCHEME: "https"
ATL_TOMCAT_SECURE: "true"
ATL_DB_DRIVER: "com.mysql.jdbc.Driver"
ATL_DB_TYPE: "mysql"
volumes:
- jiraVolume:/var/atlassian/application-data/jira
- db_data:/var/lib/mysql
ports:
- 8082:80
gitlab:
image: 'gitlab/gitlab-ce:latest'
container_name: 'gitlab'
restart: always
hostname: 'localhost'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://andio.club:443'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "email-smtp.eu-west-1.amazonaws.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "AKIAIWHHQDMPADT7ETHQ"
gitlab_rails['smtp_password'] = "AjCB8NA+61i/URp09gik0HHtbEuy48e4JXhuPaqGacFs"
gitlab_rails['smtp_domain'] = "andio.club"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
# Add any other gitlab.rb configuration here, each on its own line
gitlab_rails['gitlab_shell_ssh_port'] = 6622
ports:
- '80:80'
- '443:443'
- '6622:22'
- '587:587'
volumes:
- '/srv/gitlab/config:/etc/gitlab'
- '/srv/gitlab/logs:/var/log/gitlab'
- '/srv/gitlab/data:/var/opt/gitlab'
mysql:
image: mysql:latest
volumes:
- db_data:/var/lib/mysql
restart: always
ports:
- 33061:33061
environment:
MYSQL_ROOT_PASSWORD: andio2009
MYSQL_DATABASE: aitrainer
MYSQL_USER: aitrainer
MYSQL_PASSWORD: andio2009
networks:
- bosi_default
phpmyadmin:
depends_on:
- mysql
image: phpmyadmin/phpmyadmin
restart: always
ports:
- '8081:80'
environment:
PMA_HOST: mysql
MYSQL_ROOT_PASSWORD: andio2009
networks:
- bosi_default
php:
image: php:7.2-fpm
volumes:
- php:/var/www/html
- ./php/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mysql
gitlab-runner:
image: gitlab/gitlab-runner:latest
container_name: gitlab-runner
restart: always
networks:
- bosi_default
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /srv/gitlab-runner/config:/etc/gitlab-runner
secrets:
mysql_root_pwd:
file: /.sec/mysql_root_pwd
mysql_user_pwd:
file: /.sec/mysql_user_pwd
networks:
bosi_default:
volumes:
db_data:
php:
jiraVolume:

View File

@ -0,0 +1,31 @@
version: '3.8'
services:
mysql:
image: mysql:latest
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: andio2009
MYSQL_DATABASE: aitrainer
MYSQL_USER: aitrainer
MYSQL_PASSWORD: andio2009
volumes:
- ./docker/db:/docker-entrypoint-initdb.d
ports:
- "33061:33061"
command: mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=localhost < "/home/bosi/aitrainer/data/install.sql"
java:
image: openjdk:latest
tomcat:
image: tomcat:latest
container_name: tomcat
volumes:
- ./docker/aitrainer_server.jar:/home/bosi/aitrainer/deploy/aitrainer_server.jar
ports:
- "8080:8080"
depends_on:
- java

1
ci-cd/readme.md Normal file
View File

@ -0,0 +1 @@
jar file to deploy

View File

@ -0,0 +1,631 @@
version: '2.1'
services:
unbound-mailcow:
image: mailcow/unbound:1.12
environment:
- TZ=${TZ}
volumes:
- ./data/hooks/unbound:/hooks
- ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro
restart: always
tty: true
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.254
aliases:
- unbound
mysql-mailcow:
image: mariadb:10.3
depends_on:
- unbound-mailcow
stop_grace_period: 45s
volumes:
- mysql-vol-1:/var/lib/mysql/
- mysql-socket-vol-1:/var/run/mysqld/
- ./data/conf/mysql/:/etc/mysql/conf.d/:ro
environment:
- TZ=${TZ}
- MYSQL_ROOT_PASSWORD=${DBROOT}
- MYSQL_DATABASE=${DBNAME}
- MYSQL_USER=${DBUSER}
- MYSQL_PASSWORD=${DBPASS}
- MYSQL_INITDB_SKIP_TZINFO=1
restart: always
ports:
- "${SQL_PORT:-127.0.0.1:13306}:3306"
networks:
mailcow-network:
aliases:
- mysql
redis-mailcow:
image: redis:5-alpine
volumes:
- redis-vol-1:/data/
restart: always
ports:
- "${REDIS_PORT:-127.0.0.1:7654}:6379"
environment:
- TZ=${TZ}
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.249
aliases:
- redis
clamd-mailcow:
image: mailcow/clamd:1.36
restart: always
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
- TZ=${TZ}
- SKIP_CLAMD=${SKIP_CLAMD:-n}
volumes:
- ./data/conf/clamav/:/etc/clamav/
networks:
mailcow-network:
aliases:
- clamd
rspamd-mailcow:
image: mailcow/rspamd:1.68
stop_grace_period: 30s
depends_on:
- nginx-mailcow
- dovecot-mailcow
environment:
- TZ=${TZ}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
volumes:
- ./data/hooks/rspamd:/hooks
- ./data/conf/rspamd/custom/:/etc/rspamd/custom
- ./data/conf/rspamd/override.d/:/etc/rspamd/override.d
- ./data/conf/rspamd/local.d/:/etc/rspamd/local.d
- ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d
- ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro
- ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local
- ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override
- rspamd-vol-1:/var/lib/rspamd
restart: always
dns:
- ${IPV4_NETWORK:-172.22.1}.254
hostname: rspamd
networks:
mailcow-network:
aliases:
- rspamd
php-fpm-mailcow:
image: mailcow/phpfpm:1.63
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
depends_on:
- redis-mailcow
volumes:
- ./data/hooks/phpfpm:/hooks
- ./data/web:/web:rw
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
- ./data/conf/rspamd/custom/:/rspamd_custom_maps
- rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/
- ./data/conf/sogo/:/etc/sogo/
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
- ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/
- ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf
- ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini
- ./data/conf/phpfpm/php-conf.d/upload.ini:/usr/local/etc/php/conf.d/upload.ini
- ./data/conf/phpfpm/php-conf.d/other.ini:/usr/local/etc/php/conf.d/zzz-other.ini
- ./data/conf/dovecot/global_sieve_before:/global_sieve/before
- ./data/conf/dovecot/global_sieve_after:/global_sieve/after
- ./data/assets/templates:/tpls
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- LOG_LINES=${LOG_LINES:-9999}
- TZ=${TZ}
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- IMAP_PORT=${IMAP_PORT:-143}
- IMAPS_PORT=${IMAPS_PORT:-993}
- POP_PORT=${POP_PORT:-110}
- POPS_PORT=${POPS_PORT:-995}
- SIEVE_PORT=${SIEVE_PORT:-4190}
- SUBMISSION_PORT=${SUBMISSION_PORT:-587}
- SMTPS_PORT=${SMTPS_PORT:-465}
- SMTP_PORT=${SMTP_PORT:-25}
- API_KEY=${API_KEY:-invalid}
- API_KEY_READ_ONLY=${API_KEY_READ_ONLY:-invalid}
- API_ALLOW_FROM=${API_ALLOW_FROM:-invalid}
- COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized}
- SKIP_SOLR=${SKIP_SOLR:-y}
- SKIP_CLAMD=${SKIP_CLAMD:-n}
- SKIP_SOGO=${SKIP_SOGO:-n}
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
- MASTER=${MASTER:-y}
restart: always
networks:
mailcow-network:
aliases:
- phpfpm
sogo-mailcow:
image: mailcow/sogo:1.74
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- TZ=${TZ}
- LOG_LINES=${LOG_LINES:-9999}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- ACL_ANYONE=${ACL_ANYONE:-disallow}
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- SOGO_EXPIRE_SESSION=${SOGO_EXPIRE_SESSION:-480}
- SKIP_SOGO=${SKIP_SOGO:-n}
- MASTER=${MASTER:-y}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
dns:
- ${IPV4_NETWORK:-172.22.1}.254
volumes:
- ./data/conf/sogo/:/etc/sogo/
- ./data/web/inc/init_db.inc.php:/init_db.inc.php
- ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js
- mysql-socket-vol-1:/var/run/mysqld/
- sogo-web-vol-1:/sogo_web
- sogo-userdata-backup-vol-1:/sogo_backup
restart: always
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.248
aliases:
- sogo
dovecot-mailcow:
image: mailcow/dovecot:1.125
depends_on:
- mysql-mailcow
dns:
- ${IPV4_NETWORK:-172.22.1}.254
cap_add:
- NET_BIND_SERVICE
volumes:
- ./data/hooks/dovecot:/hooks
- ./data/conf/dovecot:/etc/dovecot
- ./data/assets/ssl:/etc/ssl/mail/:ro
- ./data/conf/sogo/:/etc/sogo/
- ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/
- vmail-vol-1:/var/vmail
- vmail-attachments-vol-1:/var/attachments
- crypt-vol-1:/mail_crypt/
- ./data/conf/rspamd/custom/:/etc/rspamd/custom
- ./data/assets/templates:/templates
- rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/
environment:
- LOG_LINES=${LOG_LINES:-9999}
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- TZ=${TZ}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
- MAILDIR_GC_TIME=${MAILDIR_GC_TIME:-1440}
- ACL_ANYONE=${ACL_ANYONE:-disallow}
- SKIP_SOLR=${SKIP_SOLR:-y}
- MAILDIR_SUB=${MAILDIR_SUB:-}
- MASTER=${MASTER:-y}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
ports:
- "${DOVEADM_PORT:-127.0.0.1:19991}:12345"
- "${IMAP_PORT:-143}:143"
- "${IMAPS_PORT:-993}:993"
- "${POP_PORT:-110}:110"
- "${POPS_PORT:-995}:995"
- "${SIEVE_PORT:-4190}:4190"
restart: always
tty: true
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
hostname: ${MAILCOW_HOSTNAME}
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.250
aliases:
- dovecot
postfix-mailcow:
image: mailcow/postfix:1.49
depends_on:
- mysql-mailcow
volumes:
- ./data/hooks/postfix:/hooks
- ./data/conf/postfix:/opt/postfix/conf
- ./data/assets/ssl:/etc/ssl/mail/:ro
- postfix-vol-1:/var/spool/postfix
- crypt-vol-1:/var/lib/zeyple
- rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/
environment:
- LOG_LINES=${LOG_LINES:-9999}
- TZ=${TZ}
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
cap_add:
- NET_BIND_SERVICE
ports:
- "${SMTP_PORT:-25}:25"
- "${SMTPS_PORT:-465}:465"
- "${SUBMISSION_PORT:-587}:587"
restart: always
dns:
- ${IPV4_NETWORK:-172.22.1}.254
hostname: ${MAILCOW_HOSTNAME}
networks:
mailcow-network:
aliases:
- postfix
memcached-mailcow:
image: memcached:alpine
restart: always
environment:
- TZ=${TZ}
networks:
mailcow-network:
aliases:
- memcached
nginx-mailcow:
depends_on:
- sogo-mailcow
- php-fpm-mailcow
- redis-mailcow
image: nginx:mainline-alpine
dns:
- ${IPV4_NETWORK:-172.22.1}.254
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
envsubst < /etc/nginx/conf.d/templates/sogo.template > /etc/nginx/conf.d/sogo.active &&
envsubst < /etc/nginx/conf.d/templates/sogo_eas.template > /etc/nginx/conf.d/sogo_eas.active &&
. /etc/nginx/conf.d/templates/sogo.auth_request.template.sh > /etc/nginx/conf.d/sogo_proxy_auth.active &&
. /etc/nginx/conf.d/templates/sites.template.sh > /etc/nginx/conf.d/sites.active &&
nginx -qt &&
until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
until ping sogo -c1 > /dev/null; do sleep 1; done &&
until ping redis -c1 > /dev/null; do sleep 1; done &&
until ping rspamd -c1 > /dev/null; do sleep 1; done &&
exec nginx -g 'daemon off;'"
environment:
- HTTPS_PORT=${HTTPS_PORT:-443}
- HTTP_PORT=${HTTP_PORT:-80}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- TZ=${TZ}
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
volumes:
- ./data/web:/web:ro
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
- ./data/assets/ssl/:/etc/ssl/mail/:ro
- ./data/conf/nginx/:/etc/nginx/conf.d/:rw
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
- sogo-web-vol-1:/usr/lib/GNUstep/SOGo/
ports:
- "${HTTPS_BIND:-0.0.0.0}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}"
- "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}"
restart: always
networks:
mailcow-network:
aliases:
- nginx
acme-mailcow:
depends_on:
- nginx-mailcow
image: mailcow/acme:1.70
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
- LOG_LINES=${LOG_LINES:-9999}
- ADDITIONAL_SAN=${ADDITIONAL_SAN}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n}
- ENABLE_SSL_SNI=${ENABLE_SSL_SNI:-n}
- SKIP_IP_CHECK=${SKIP_IP_CHECK:-n}
- SKIP_HTTP_VERIFICATION=${SKIP_HTTP_VERIFICATION:-n}
- ONLY_MAILCOW_HOSTNAME=${ONLY_MAILCOW_HOSTNAME:-n}
- LE_STAGING=${LE_STAGING:-n}
- TZ=${TZ}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
volumes:
- ./data/web/.well-known/acme-challenge:/var/www/acme:rw
- ./data/assets/ssl:/var/lib/acme/:rw
- ./data/assets/ssl-example:/var/lib/ssl-example/:ro
- mysql-socket-vol-1:/var/run/mysqld/
restart: always
networks:
mailcow-network:
aliases:
- acme
netfilter-mailcow:
image: mailcow/netfilter:1.36
stop_grace_period: 30s
depends_on:
- dovecot-mailcow
- postfix-mailcow
- sogo-mailcow
- php-fpm-mailcow
- redis-mailcow
restart: always
privileged: true
environment:
- TZ=${TZ}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
- SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
network_mode: "host"
volumes:
- /lib/modules:/lib/modules:ro
watchdog-mailcow:
image: mailcow/watchdog:1.77
# Debug
#command: /watchdog.sh
dns:
- ${IPV4_NETWORK:-172.22.1}.254
volumes:
- rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/
- ./data/assets/ssl:/etc/ssl/mail/:ro
restart: always
environment:
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
- LOG_LINES=${LOG_LINES:-9999}
- TZ=${TZ}
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- DBROOT=${DBROOT}
- USE_WATCHDOG=${USE_WATCHDOG:-n}
- WATCHDOG_NOTIFY_EMAIL=${WATCHDOG_NOTIFY_EMAIL}
- WATCHDOG_NOTIFY_BAN=${WATCHDOG_NOTIFY_BAN:-y}
- WATCHDOG_EXTERNAL_CHECKS=${WATCHDOG_EXTERNAL_CHECKS:-n}
- WATCHDOG_MYSQL_REPLICATION_CHECKS=${WATCHDOG_MYSQL_REPLICATION_CHECKS:-n}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
- IP_BY_DOCKER_API=${IP_BY_DOCKER_API:-0}
- CHECK_UNBOUND=${CHECK_UNBOUND:-1}
- SKIP_CLAMD=${SKIP_CLAMD:-n}
- SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n}
- SKIP_SOGO=${SKIP_SOGO:-n}
- HTTPS_PORT=${HTTPS_PORT:-443}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- EXTERNAL_CHECKS_THRESHOLD=1
- NGINX_THRESHOLD=5
- UNBOUND_THRESHOLD=5
- REDIS_THRESHOLD=5
- MYSQL_THRESHOLD=5
- MYSQL_REPLICATION_THRESHOLD=1
- SOGO_THRESHOLD=3
- POSTFIX_THRESHOLD=8
- CLAMD_THRESHOLD=15
- DOVECOT_THRESHOLD=12
- DOVECOT_REPL_THRESHOLD=2
- PHPFPM_THRESHOLD=5
- RATELIMIT_THRESHOLD=1
- FAIL2BAN_THRESHOLD=1
- ACME_THRESHOLD=1
- IPV6NAT_THRESHOLD=1
- RSPAMD_THRESHOLD=5
- OLEFY_THRESHOLD=5
networks:
mailcow-network:
aliases:
- watchdog
dockerapi-mailcow:
image: mailcow/dockerapi:1.37
restart: always
oom_kill_disable: true
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
- DBROOT=${DBROOT}
- TZ=${TZ}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
mailcow-network:
aliases:
- dockerapi
solr-mailcow:
image: mailcow/solr:1.7
restart: always
volumes:
- solr-vol-1:/opt/solr/server/solr/dovecot-fts/data
ports:
- "${SOLR_PORT:-127.0.0.1:18983}:8983"
environment:
- TZ=${TZ}
- SOLR_HEAP=${SOLR_HEAP:-1024}
- SKIP_SOLR=${SKIP_SOLR:-y}
networks:
mailcow-network:
aliases:
- solr
olefy-mailcow:
image: mailcow/olefy:1.3
restart: always
environment:
- TZ=${TZ}
- OLEFY_BINDADDRESS=0.0.0.0
- OLEFY_BINDPORT=10055
- OLEFY_TMPDIR=/tmp
- OLEFY_PYTHON_PATH=/usr/bin/python3
- OLEFY_OLEVBA_PATH=/usr/bin/olevba3
- OLEFY_LOGLVL=20
- OLEFY_MINLENGTH=500
- OLEFY_DEL_TMP=1
networks:
mailcow-network:
aliases:
- olefy
ipv6nat-mailcow:
depends_on:
- unbound-mailcow
- mysql-mailcow
- redis-mailcow
- clamd-mailcow
- rspamd-mailcow
- php-fpm-mailcow
- sogo-mailcow
- dovecot-mailcow
- postfix-mailcow
- memcached-mailcow
- nginx-mailcow
- acme-mailcow
- netfilter-mailcow
- watchdog-mailcow
- dockerapi-mailcow
- solr-mailcow
environment:
- TZ=${TZ}
image: robbertkl/ipv6nat
restart: always
privileged: true
network_mode: "host"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro
gitlab:
image: 'gitlab/gitlab-ce:latest'
container_name: 'gitlab'
restart: always
hostname: 'localhost'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://aitrainer.app:8929'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "email-smtp.eu-west-1.amazonaws.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "AKIAIWHHQDMPADT7ETHQ"
gitlab_rails['smtp_password'] = "AjCB8NA+61i/URp09gik0HHtbEuy48e4JXhuPaqGacFs"
gitlab_rails['smtp_domain'] = "aitrainer.app"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
# Add any other gitlab.rb configuration here, each on its own line
gitlab_rails['gitlab_shell_ssh_port'] = 6622
ports:
- '8929:8929'
- '443:443'
- '6622:22'
- '587:587'
volumes:
- '/srv/gitlab/config:/etc/gitlab'
- '/srv/gitlab/logs:/var/log/gitlab'
- '/srv/gitlab/data:/var/opt/gitlab'
mysql:
image: mysql:latest
volumes:
- mysql-vol-0:/var/lib/mysql0
restart: always
ports:
- 33061:33061
environment:
MYSQL_ROOT_PASSWORD: /run/secrets/mysql_root_pwd
MYSQL_DATABASE: aitrainer
MYSQL_USER: aitrainer
MYSQL_PASSWORD: /run/secrets/mysql_user_pwd
networks:
- bosi_default
phpmyadmin:
depends_on:
- mysql
image: phpmyadmin/phpmyadmin
restart: always
ports:
- '80:80'
environment:
PMA_HOST: mysql
MYSQL_ROOT_PASSWORD: andio2009
networks:
- bosi_default
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /srv/gitlab-runner/config:/etc/gitlab-runner
networks:
bosi_default:
mailcow-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-mailcow
enable_ipv6: true
ipam:
driver: default
config:
- subnet: ${IPV4_NETWORK:-172.22.1}.0/24
- subnet: ${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
volumes:
# Storage for email files
vmail-vol-1:
# Storage for attachments (deduplicated)
vmail-attachments-vol-1:
mysql-vol-1:
mysql-vol-0:
mysql-socket-vol-1:
redis-vol-1:
rspamd-vol-1:
solr-vol-1:
postfix-vol-1:
crypt-vol-1:
sogo-web-vol-1:
sogo-userdata-backup-vol-1:
php:
secrets:
mysql_root_pwd:
file: /.sec/mysql_root_pwd
mysql_user_pwd:
file: /.sec/mysql_user_pwd

View File

@ -0,0 +1,143 @@
version: '3.8'
services:
demo:
image: ehazlett/docker-demo
deploy:
replicas: 1
labels:
com.docker.lb.hosts: aitrainer.app
com.docker.lb.network: bosi-network
com.docker.lb.port: 8080
com.docker.lb.ssl_cert: demo_app.example.org.cert
com.docker.lb.ssl_key: demo_app.example.org.key
environment:
METADATA: proxy-handles-tls
networks:
- demo-network
gitlab:
image: 'gitlab/gitlab-ce:latest'
container_name: 'gitlab'
restart: always
hostname: 'localhost'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://aitrainer.app'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "email-smtp.eu-west-1.amazonaws.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "AKIAIWHHQDMPADT7ETHQ"
gitlab_rails['smtp_password'] = "AjCB8NA+61i/URp09gik0HHtbEuy48e4JXhuPaqGacFs"
gitlab_rails['smtp_domain'] = "aitrainer.app"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
# Add any other gitlab.rb configuration here, each on its own line
gitlab_rails['gitlab_shell_ssh_port'] = 6622
ports:
- '80:80'
- '443:443'
- '6622:22'
- '587:587'
volumes:
- '/srv/gitlab/config:/etc/gitlab'
- '/srv/gitlab/logs:/var/log/gitlab'
- '/srv/gitlab/data:/var/opt/gitlab'
mysql:
image: mysql:latest
volumes:
- db_data:/var/lib/mysql_aitrainer
restart: always
ports:
- 33061:33061
environment:
MYSQL_ROOT_PASSWORD: /run/secrets/mysql_root_pwd
MYSQL_DATABASE: aitrainer
MYSQL_USER: aitrainer
MYSQL_PASSWORD: /run/secrets/mysql_user_pwd
networks:
- bosi_default
phpmyadmin:
depends_on:
- mysql
image: phpmyadmin/phpmyadmin
restart: always
ports:
- '8081:80'
environment:
PMA_HOST: mysql
MYSQL_ROOT_PASSWORD: andio2009
networks:
- bosi_default
php:
image: php:7.2-fpm
volumes:
- php:/var/www/html
- ./php/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mysql
gitlab-runner:
image: gitlab/gitlab-runner:latest
container_name: gitlab-runner
restart: always
networks:
- bosi_default
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /srv/gitlab-runner/config:/etc/gitlab-runner
secrets:
mysql_root_pwd:
file: /.sec/mysql_root_pwd
mysql_user_pwd:
file: /.sec/mysql_user_pwd
networks:
bosi_default:
volumes:
db_data:
php:
openssl req \
-new \
-newkey rsa:4096 \
-days 3650 \
-nodes \
-x509 \
-subj "/C=US/ST=CA/L=SF/O=Docker-demo/CN=aitrainer.app" \
-keyout aitrainer.app.key \
-out aitrainer.app.cert
version: "3.2"
services:
demo:
image: proxy
command: --tls-cert=/run/secrets/cert.pem --tls-key=/run/secrets/key.pem
deploy:
replicas: 1
labels:
com.docker.lb.hosts: aitrainer.app
com.docker.lb.network: proxy-network
com.docker.lb.port: 8029
com.docker.lb.ssl_passthrough: "true"
environment:
METADATA: end-to-end-TLS
networks:
- proxy-network
secrets:
- source: aitrainer.app.cert
target: /run/secrets/cert.pem
- source: aitrainer.app.org.key
target: /run/secrets/key.pem
networks:
demo-network:
driver: overlay
secrets:
aitrainer.app.cert:
file: ./aitrainer.app.cert
aitrainer.app.key:
file: ./aitrainer.app.key

View File

@ -0,0 +1,113 @@
## GitLab
##
## Modified from nginx http version
## Modified from http://blog.phusion.nl/2012/04/21/tutorial-setting-up-gitlab-on-debian-6/
## Modified from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
##
## Lines starting with two hashes (##) are comments with information.
## Lines starting with one hash (#) are configuration parameters that can be uncommented.
##
##################################
## CONTRIBUTING ##
##################################
##
## If you change this file in a Merge Request, please also create
## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
##
###################################
## configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab-workhorse {
server unix:/srv/gitlab/gitlab-workhorse/socket fail_timeout=0;
}
## Redirects all HTTP traffic to the HTTPS host
server {
## Either remove "default_server" from the listen line below,
## or delete the /etc/nginx/sites-enabled/default file. This will cause gitlab
## to be served if you visit any address that your server responds to, eg.
## the ip address of the server (http://x.x.x.x/)
listen 0.0.0.0:80;
listen [::]:80 ipv6only=on default_server;
server_name git.aitrainer.app ; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
return 301 https://$http_host$request_uri;
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
}
## HTTPS host
server {
listen 0.0.0.0:443 ssl;
listen [::]:443 ipv6only=on ssl default_server;
server_name git.aitrainer.app ; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
root /opt/gitlab/embedded/service/gitlab-rails/public;
## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
ssl on;
#ssl_certificate /etc/nginx/ssl/gitlab.crt;
#ssl_certificate_key /etc/nginx/ssl/gitlab.key;
ssl_certificate /etc/letsencrypt/live/git.aitrainer.app/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/git.aitrainer.app/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
## See app/controllers/application_controller.rb for headers set
## [Optional] Enable HTTP Strict Transport Security
## HSTS is a feature improving protection against MITM attacks
## For more information see: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL.
## Replace with your ssl_trusted_certificate. For more info see:
## - https://medium.com/devops-programming/4445f4862461
## - https://www.ruby-forum.com/topic/4419319
## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
# resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
# resolver_timeout 5s;
## [Optional] Generate a stronger DHE parameter:
## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
##
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
location / {
client_max_body_size 0;
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-workhorse;
}
}

138
data/db/install.sql Normal file
View File

@ -0,0 +1,138 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Szerver verzió: 10.4.11-MariaDB - mariadb.org binary distribution
-- Szerver OS: Win64
-- HeidiSQL Verzió: 11.0.0.5919
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
use aitrainer;
-- Struktúra mentése tábla aitrainer. customer
CREATE TABLE IF NOT EXISTS `customer` (
`customer_id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(100) COLLATE utf8_hungarian_ci NOT NULL,
`firstname` char(100) COLLATE utf8_hungarian_ci NOT NULL,
`email` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL,
`password` char(100) COLLATE utf8_hungarian_ci DEFAULT NULL,
`sex` enum('m','w') COLLATE utf8_hungarian_ci DEFAULT 'm',
`age` tinyint(4) DEFAULT NULL,
`active` enum('Y','N','D','S') COLLATE utf8_hungarian_ci DEFAULT 'N',
`date_add` datetime DEFAULT NULL,
`date_change` datetime DEFAULT NULL,
`data_policy_allowed` tinyint(4) DEFAULT 1,
`admin` tinyint(4) DEFAULT 0,
PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.customer: ~13 rows (hozzávetőleg)
/*!40000 ALTER TABLE `customer` DISABLE KEYS */;
INSERT INTO `customer` (`customer_id`, `name`, `firstname`, `email`, `password`, `sex`, `age`, `active`, `date_add`, `date_change`, `data_policy_allowed`, `admin`) VALUES
(1, 'Átlag 13 éves fiú', '', NULL, NULL, 'm', 13, 'N', NULL, NULL, 1, 0),
(2, 'Átlag 14 éves fiú', '', NULL, NULL, 'm', 14, 'N', NULL, NULL, 1, 0),
(3, 'Átlag 15 éves fiú', '', NULL, NULL, 'm', 15, 'N', NULL, NULL, 1, 0),
(4, 'Átlag 15 éves fiú', '', NULL, NULL, 'm', 15, 'N', NULL, NULL, 1, 0),
(5, 'Átlag 16 éves fiú', '', NULL, NULL, 'm', 16, 'N', NULL, NULL, 1, 0),
(6, 'Átlag 17 éves fiú', '', NULL, NULL, 'm', 17, 'N', NULL, NULL, 1, 0),
(7, 'Átlag 18 éves fiú', '', NULL, NULL, 'm', 18, 'N', NULL, NULL, 1, 0),
(8, 'Átlag 13 éves lány', '', NULL, NULL, 'w', 13, 'N', NULL, NULL, 1, 0),
(9, 'Átlag 14 éves lány', '', NULL, NULL, 'w', 14, 'N', NULL, NULL, 1, 0),
(10, 'Átlag 15 éves lány', '', NULL, NULL, 'w', 15, 'N', NULL, NULL, 1, 0),
(11, 'Átlag 16 éves lány', '', NULL, NULL, 'w', 16, 'N', NULL, NULL, 1, 0),
(12, 'Átlag 17 éves lány', '', NULL, NULL, 'w', 17, 'N', NULL, NULL, 1, 0),
(13, 'Átlag 18 éves lány', '', NULL, NULL, 'w', 18, 'N', NULL, NULL, 1, 0);
/*!40000 ALTER TABLE `customer` ENABLE KEYS */;
-- Struktúra mentése tábla aitrainer. customer_information
CREATE TABLE IF NOT EXISTS `customer_information` (
`customer_information_id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(50) COLLATE utf8_hungarian_ci DEFAULT '',
`description` mediumtext COLLATE utf8_hungarian_ci DEFAULT NULL,
`date_add` datetime DEFAULT NULL,
`display_begin` datetime DEFAULT NULL,
`display_end` datetime DEFAULT NULL,
PRIMARY KEY (`customer_information_id`) USING BTREE,
KEY `title` (`title`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.customer_information: ~0 rows (hozzávetőleg)
/*!40000 ALTER TABLE `customer_information` DISABLE KEYS */;
/*!40000 ALTER TABLE `customer_information` ENABLE KEYS */;
INSERT INTO `customer_information` (`customer_information_id`, `title`, `description`, `date_add`, `display_begin`, `display_end`) VALUES (1, 'Fekvőtámasz világcsúcs', 'Világcsúcs fekvőtámasz: KJ Joseph 1 perc alatt 82 szabályos fekvőtámaszt végzett', '2020-06-01 08:00:00', '2020-06-01 08:00:00', '2023-07-01 08:00:00');
INSERT INTO `customer_information` (`customer_information_id`, `title`, `description`, `date_add`, `display_begin`, `display_end`) VALUES (2, 'Húzódszkodás csúcs', '24 órás csúcstartója Joonas Mäkipelto 5050 gyakorlattal', '2020-06-01 08:00:00', '2020-06-01 08:00:00', '2023-07-01 08:00:00');
INSERT INTO `customer_information` (`customer_information_id`, `title`, `description`, `date_add`, `display_begin`, `display_end`) VALUES (3, 'Fekvenyomás', '2015-ben a fekvenyomó világbajnokságot Smulter Fredrik finn súlyemelő 401 Kg-al nyerte', '2020-06-01 08:00:00', '2020-05-01 00:00:00', '2020-06-01 08:00:01');
-- Struktúra mentése tábla aitrainer. exercises
CREATE TABLE IF NOT EXISTS `exercises` (
`exercise_id` int(11) NOT NULL AUTO_INCREMENT,
`exercise_type_id` int(11) NOT NULL,
`customer_id` int(11) NOT NULL,
`date_add` datetime NOT NULL,
`quantity` float DEFAULT NULL,
`unit` enum('kg','meter','repeat','minute') COLLATE utf8_hungarian_ci DEFAULT 'repeat',
`rest_time` int(11) DEFAULT NULL COMMENT 'in sec',
PRIMARY KEY (`exercise_id`),
KEY `exercise_type_id` (`exercise_type_id`),
KEY `customer_id` (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.exercises: ~0 rows (hozzávetőleg)
/*!40000 ALTER TABLE `exercises` DISABLE KEYS */;
INSERT INTO `exercises` (`exercise_id`, `exercise_type_id`, `customer_id`, `date_add`, `quantity`, `unit`, `rest_time`) VALUES
(1, 1, 1, '2020-05-01 00:00:00', 12, 'repeat', NULL);
/*!40000 ALTER TABLE `exercises` ENABLE KEYS */;
-- Struktúra mentése tábla aitrainer. exercise_evaluation
CREATE TABLE IF NOT EXISTS `exercise_evaluation` (
`evaluation_id` int(11) NOT NULL AUTO_INCREMENT,
`age_min` int(11) DEFAULT 0,
`age_max` int(11) DEFAULT 0,
`value_min` int(11) DEFAULT 0,
`value_max` int(11) DEFAULT 0,
`sex` enum('m','w') COLLATE utf8_hungarian_ci NOT NULL DEFAULT 'm',
`evaluation` enum('excellent','very good','good','average','weak','poor') COLLATE utf8_hungarian_ci NOT NULL DEFAULT 'average',
`description` mediumtext COLLATE utf8_hungarian_ci DEFAULT NULL,
PRIMARY KEY (`evaluation_id`) USING BTREE,
KEY `value_min_value_max` (`value_min`,`value_max`) USING BTREE,
KEY `age_min_age_max` (`age_min`,`age_max`) USING BTREE,
KEY `age_min_age_max_value_min_value_max` (`age_min`,`age_max`,`value_min`,`value_max`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.exercise_evaluation: ~0 rows (hozzávetőleg)
/*!40000 ALTER TABLE `exercise_evaluation` DISABLE KEYS */;
/*!40000 ALTER TABLE `exercise_evaluation` ENABLE KEYS */;
-- Struktúra mentése tábla aitrainer. exercise_type
CREATE TABLE IF NOT EXISTS `exercise_type` (
`exercise_type_id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(100) COLLATE utf8_hungarian_ci NOT NULL,
`description` varchar(1000) COLLATE utf8_hungarian_ci DEFAULT NULL,
`video` mediumblob DEFAULT NULL,
PRIMARY KEY (`exercise_type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.exercise_type: ~11 rows (hozzávetőleg)
/*!40000 ALTER TABLE `exercise_type` DISABLE KEYS */;
INSERT INTO `exercise_type` (`exercise_type_id`, `name`, `description`, `video`) VALUES
(1, 'Melső fekvőtámasz 1 perc', 'Ezt igazolja a 2016 márciusában beállított guinness rekord is,\r\namelyben KJ Joseph 1 perc alatt 82 szabályos karhajlítás-nyújtást\r\nvégzett.', NULL),
(2, 'Húzódzkodás', 'Ennek a gyakorlatnak a 24 órás csúcstartója Joonas Mäkipelto 5050\r\ngyakorlattal.', NULL),
(3, 'Melső fekvőtámasz 30mp', 'A gyakorlatot 30 másodperc alatt olyan sokszor kell végrehajtani, ahányszor a\r\nfelvételiző képes rá. Azonban törekedni kell a szabályos végrehajtásra, ugyanis csak azokat\r\nszámolják. A nők esetében 20, a férfiak esetében 35 gyakorlatot kell végrehajtani a maximális\r\npont megszerzéséért. A gyakorlat akkor sikeres, ha a női legalább 1, a férfi felvételiző\r\nlegalább 11 gyakorlatot képes végrehajtani.', NULL),
(4, 'Melső fekvőtámasz 2perc', 'Magyar Honvédség: A gyakorlat végrehajtására 2 perc áll rendelkezésre. Ennek során csak a szabályosan a\r\nfentiekben leírt módon végrehajtott gyakorlat értékelhető. Férfiaknál 70 karhajlítás nyújtást\r\nkell végrehajtani a maximális pontért.', NULL),
(5, 'Hajlított karú függés', 'A gyakorlat addig tart, amíg a végrehajtó szemmagassága a kiinduló helyzettől\r\nsüllyedve a keresztvas alá nem kerül. Az értékeléshez stopperórát alkalmaznak, és az\r\neredmény másodperc pontossággal kerül megállapításra. Nők esetében 45, férfiak\r\ntekintetében 73 másodperctől jár a maximális pontszám. A gyakorlat sikeres végrehajtásához\r\nlegalább 8, 10 másodpercig kell megtartaniuk a kiinduló helyzetet a női és a férfi\r\nfelvételizőknek.\r\n\r\nA NKE-RTK-án lévő hallgatók egyéni rekordjai Iván Viktor 90s, Kiss Regina 74s', NULL),
(6, 'Fekvenyomás', '2015-ben a fekvenyomó világbajnokságot Smulter Fredrik finn súlyemelő 401 Kg-al nyerte.\r\nA súlyzó tömege nők esetében 25 kg, a férfiak esetében 60 kg a rúddal együtt. Az\r\nértékelésénél a szabályosan végrehajtott gyakorlatokat értékelik csak.\r\nA legtöbb pontért 25 gyakorlatot kell végezni mind a nőknek, mind a férfiaknak. A minimum:\r\negy gyakorlat mindkét nem esetében.', NULL),
(7, '4x10m-es ingafutás', 'A legjobb pontszámért 9,4 s illetve 8,8s alatt kell teljesíteni a nőknek, férfiaknak. A\r\ngyakorlat sikertelen 11,8 s illetve 11,2 s-on túl.', NULL),
(8, 'Helyből távolugrás', 'Byron Jones 2015-ben a 3,73 méteres ugrásával érte el a világcsúcsot.\r\nA nőknek 220 cm-re, a férfiak 250 cm-re kell ugraniuk a maximális pontért. A\r\nminimális távolság 172cm illetve 198 cm.', NULL),
(9, 'Felülés hanyattfekvésből', 'Az NKE-RTK hallgatói közül Papp Zsófia 66 db-ot, Gál Valentin 80\r\ndb-ot csinált 1 perc leforgása alatt.\r\nElső ütemre megtörténik a felülés, ami akkor szabályos, ha valamelyik könyök érinti a\r\ntérdet. Második ütemre vissza kell térni a kiinduló helyzetbe. A maximális pont eléréséhez 1\r\nperc alatt 45 illetve 55 ismétlést kell végezni a nőknek illetve a férfiaknak. A minimumhoz 7\r\nés 25 ismétlés szükséges.', NULL),
(10, 'Felülés hajlított térddel', 'Magyar Honvédség: A kiinduló helyzet hajlított ülés, ennek során a sarkak a talajon, a térd 90 fokban meghajlítva\r\nvan.\r\nA gyakorlat végrehajtására két perc áll rendelkezésre. Ennek során csak a szabályosan,\r\na fentiekben leírt módon végrehajtott gyakorlat értékelhető. Férfiaknál, nőknél egyaránt 90\r\ngyakorlatot kell végrehajtani a maximális pontért. Amennyiben a megadott időkeret alatt nem\r\nsikerül legalább 25 szabályos gyakorlatot végrehajtani, úgy az sikertelennek minősül.', NULL),
(11, 'Síkfutás 2000m', 'A maximálisan megszerezhető pontot az a felvételiző gyűjtheti be, aki a távot nők\r\nesetében 10:00 perc alatt, férfiak esetében 7:35 perc alatt teljesíti. A gyakorlat sikeres\r\nteljesítésére nők esetében maximum 16:00 perc, férfiak esetében 13:30 perc áll rendelkezésre.', NULL);
/*!40000 ALTER TABLE `exercise_type` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

115
data/db/install_0_0_1.sql Normal file
View File

@ -0,0 +1,115 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Szerver verzió: 8.0.20 - MySQL Community Server - GPL
-- Szerver OS: Win64
-- HeidiSQL Verzió: 11.0.0.5919
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
use aitrainer;
-- Struktúra mentése tábla aitrainer. customer
CREATE TABLE IF NOT EXISTS `customer` (
`customer_id` int NOT NULL AUTO_INCREMENT,
`name` char(100) NOT NULL,
`firstname` char(100) NOT NULL,
`email` char(100) DEFAULT NULL,
`sex` enum('m','w') DEFAULT 'm',
`age` tinyint DEFAULT NULL,
`active` enum('Y','N','D','S') DEFAULT 'N',
PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.customer: ~15 rows (hozzávetőleg)
/*!40000 ALTER TABLE `customer` DISABLE KEYS */;
INSERT INTO `customer` (`customer_id`, `name`, `firstname`, `email`, `sex`, `age`) VALUES
(1, 'Átlag 13 éves fiú', '', NULL, 'm', 13),
(2, 'Átlag 14 éves fiú', '', NULL, 'm', 14),
(3, 'Átlag 15 éves fiú', '', NULL, 'm', 15),
(4, 'Átlag 15 éves fiú', '', NULL, 'm', 15),
(5, 'Átlag 16 éves fiú', '', NULL, 'm', 16),
(6, 'Átlag 17 éves fiú', '', NULL, 'm', 17),
(7, 'Átlag 18 éves fiú', '', NULL, 'm', 18),
(8, 'Átlag 13 éves lány', '', NULL, 'w', 13),
(9, 'Átlag 14 éves lány', '', NULL, 'w', 14),
(10, 'Átlag 15 éves lány', '', NULL, 'w', 15),
(11, 'Átlag 16 éves lány', '', NULL, 'w', 16),
(12, 'Átlag 17 éves lány', '', NULL, 'w', 17),
(13, 'Átlag 18 éves lány', '', NULL, 'w', 18);
/*!40000 ALTER TABLE `customer` ENABLE KEYS */;
-- Struktúra mentése tábla aitrainer. exercises
CREATE TABLE IF NOT EXISTS `exercises` (
`exercise_id` int NOT NULL AUTO_INCREMENT,
`exercise_type_id` int NOT NULL,
`customer_id` int NOT NULL,
`datetime_exercise` datetime NOT NULL,
`quantity` float DEFAULT NULL,
`rest_time` int DEFAULT NULL COMMENT 'in sec',
PRIMARY KEY (`exercise_id`),
KEY `exercise_type_id` (`exercise_type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.exercises: ~1 rows (hozzávetőleg)
/*!40000 ALTER TABLE `exercises` DISABLE KEYS */;
INSERT INTO `exercises` (`exercise_id`, `exercise_type_id`, `customer_id`, `datetime_exercise`, `quantity`, `rest_time`) VALUES
(1, 1, 1, '2020-05-01 00:00:00', 12, NULL);
/*!40000 ALTER TABLE `exercises` ENABLE KEYS */;
-- Struktúra mentése tábla aitrainer. exercise_ages
CREATE TABLE IF NOT EXISTS `exercise_ages` (
`exercise_age_id` int NOT NULL AUTO_INCREMENT,
`exercise_type_id` int NOT NULL,
`name` char(100) NOT NULL,
`sex` enum('m','w') DEFAULT 'm',
`age` tinyint DEFAULT NULL,
`min_exercises` int DEFAULT NULL,
`avg_exercises` int DEFAULT NULL,
`max_exercises` int DEFAULT NULL,
PRIMARY KEY (`exercise_age_id`),
UNIQUE KEY `exercise_type_id_2` (`exercise_type_id`,`sex`,`age`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.exercise_ages: ~6 rows (hozzávetőleg)
/*!40000 ALTER TABLE `exercise_ages` DISABLE KEYS */;
INSERT INTO `exercise_ages` (`exercise_age_id`, `exercise_type_id`, `name`, `sex`, `age`, `min_exercises`, `avg_exercises`, `max_exercises`) VALUES
(1, 1, '', 'm', 13, 12, NULL, NULL),
(2, 1, '', 'm', 14, 14, NULL, NULL),
(3, 1, '', 'm', 15, 16, NULL, NULL),
(4, 1, '', 'm', 16, 18, NULL, NULL),
(7, 1, '', 'm', 17, 18, NULL, NULL),
(8, 1, '', 'm', 18, 18, NULL, NULL);
/*!40000 ALTER TABLE `exercise_ages` ENABLE KEYS */;
-- Struktúra mentése tábla aitrainer. exercise_types
CREATE TABLE IF NOT EXISTS `exercise_type` (
`exercise_type_id` int NOT NULL AUTO_INCREMENT,
`name` char(100) NOT NULL,
`description` varchar(1000) DEFAULT NULL,
`video` mediumblob,
PRIMARY KEY (`exercise_type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_hungarian_ci;
-- Tábla adatainak mentése aitrainer.exercise_types: ~11 rows (hozzávetőleg)
/*!40000 ALTER TABLE `exercise_type` DISABLE KEYS */;
INSERT INTO `exercise_type` (`exercise_type_id`, `name`, `description`, `video`) VALUES
(1, 'Melső fekvőtámasz 1 perc', 'Ezt igazolja a 2016 márciusában beállított guinness rekord is,\r\namelyben KJ Joseph 1 perc alatt 82 szabályos karhajlítás-nyújtást\r\nvégzett.', NULL),
(2, 'Húzódzkodás', 'Ennek a gyakorlatnak a 24 órás csúcstartója Joonas Mäkipelto 5050\r\ngyakorlattal.', NULL),
(3, 'Melső fekvőtámasz 30mp', 'A gyakorlatot 30 másodperc alatt olyan sokszor kell végrehajtani, ahányszor a\r\nfelvételiző képes rá. Azonban törekedni kell a szabályos végrehajtásra, ugyanis csak azokat\r\nszámolják. A nők esetében 20, a férfiak esetében 35 gyakorlatot kell végrehajtani a maximális\r\npont megszerzéséért. A gyakorlat akkor sikeres, ha a női legalább 1, a férfi felvételiző\r\nlegalább 11 gyakorlatot képes végrehajtani.', NULL),
(4, 'Melső fekvőtámasz 2perc', 'Magyar Honvédség: A gyakorlat végrehajtására 2 perc áll rendelkezésre. Ennek során csak a szabályosan a\r\nfentiekben leírt módon végrehajtott gyakorlat értékelhető. Férfiaknál 70 karhajlítás nyújtást\r\nkell végrehajtani a maximális pontért.', NULL),
(5, 'Hajlított karú függés', 'A gyakorlat addig tart, amíg a végrehajtó szemmagassága a kiinduló helyzettől\r\nsüllyedve a keresztvas alá nem kerül. Az értékeléshez stopperórát alkalmaznak, és az\r\neredmény másodperc pontossággal kerül megállapításra. Nők esetében 45, férfiak\r\ntekintetében 73 másodperctől jár a maximális pontszám. A gyakorlat sikeres végrehajtásához\r\nlegalább 8, 10 másodpercig kell megtartaniuk a kiinduló helyzetet a női és a férfi\r\nfelvételizőknek.\r\n\r\nA NKE-RTK-án lévő hallgatók egyéni rekordjai Iván Viktor 90s, Kiss Regina 74s', NULL),
(6, 'Fekvenyomás', '2015-ben a fekvenyomó világbajnokságot Smulter Fredrik finn súlyemelő 401 Kg-al nyerte.\r\nA súlyzó tömege nők esetében 25 kg, a férfiak esetében 60 kg a rúddal együtt. Az\r\nértékelésénél a szabályosan végrehajtott gyakorlatokat értékelik csak.\r\nA legtöbb pontért 25 gyakorlatot kell végezni mind a nőknek, mind a férfiaknak. A minimum:\r\negy gyakorlat mindkét nem esetében.', NULL),
(7, '4x10m-es ingafutás', 'A legjobb pontszámért 9,4 s illetve 8,8s alatt kell teljesíteni a nőknek, férfiaknak. A\r\ngyakorlat sikertelen 11,8 s illetve 11,2 s-on túl.', NULL),
(8, 'Helyből távolugrás', 'Byron Jones 2015-ben a 3,73 méteres ugrásával érte el a világcsúcsot.\r\nA nőknek 220 cm-re, a férfiak 250 cm-re kell ugraniuk a maximális pontért. A\r\nminimális távolság 172cm illetve 198 cm.', NULL),
(9, 'Felülés hanyattfekvésből', 'Az NKE-RTK hallgatói közül Papp Zsófia 66 db-ot, Gál Valentin 80\r\ndb-ot csinált 1 perc leforgása alatt.\r\nElső ütemre megtörténik a felülés, ami akkor szabályos, ha valamelyik könyök érinti a\r\ntérdet. Második ütemre vissza kell térni a kiinduló helyzetbe. A maximális pont eléréséhez 1\r\nperc alatt 45 illetve 55 ismétlést kell végezni a nőknek illetve a férfiaknak. A minimumhoz 7\r\nés 25 ismétlés szükséges.', NULL),
(10, 'Felülés hajlított térddel', 'Magyar Honvédség: A kiinduló helyzet hajlított ülés, ennek során a sarkak a talajon, a térd 90 fokban meghajlítva\r\nvan.\r\nA gyakorlat végrehajtására két perc áll rendelkezésre. Ennek során csak a szabályosan,\r\na fentiekben leírt módon végrehajtott gyakorlat értékelhető. Férfiaknál, nőknél egyaránt 90\r\ngyakorlatot kell végrehajtani a maximális pontért. Amennyiben a megadott időkeret alatt nem\r\nsikerül legalább 25 szabályos gyakorlatot végrehajtani, úgy az sikertelennek minősül.', NULL),
(11, 'Síkfutás 2000m', 'A maximálisan megszerezhető pontot az a felvételiző gyűjtheti be, aki a távot nők\r\nesetében 10:00 perc alatt, férfiak esetében 7:35 perc alatt teljesíti. A gyakorlat sikeres\r\nteljesítésére nők esetében maximum 16:00 perc, férfiak esetében 13:30 perc áll rendelkezésre.', NULL);
/*!40000 ALTER TABLE `exercise_type` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

55
data/db/update_0_0_2.sql Normal file
View File

@ -0,0 +1,55 @@
ALTER TABLE `exercises`
ADD COLUMN `unit` ENUM('kg','meter','repeat','minute') NULL DEFAULT 'repeat' AFTER `quantity`,
CHANGE COLUMN `quantity` `quantity` FLOAT NULL DEFAULT NULL AFTER `datetime_exercise`;
ALTER TABLE `exercises`
CHANGE COLUMN `datetime_exercise` `date_add` DATETIME NOT NULL AFTER `customer_id`,
ADD INDEX `customer_id` (`customer_id`);
ALTER TABLE `customer`
ADD COLUMN `password` CHAR(100) NULL DEFAULT NULL AFTER `email`,
ADD COLUMN `date_add` DATETIME NULL AFTER `active`,
ADD COLUMN `date_change` DATETIME NULL AFTER `date_add`,
ADD COLUMN `data_policy_allowed` TINYINT NULL DEFAULT '1' AFTER `date_change`,
ADD COLUMN `admin` TINYINT NULL DEFAULT '0' AFTER `data_policy_allowed`;
CREATE TABLE `exercise_evaluation` (
`evaluation_id` INT(11) NOT NULL AUTO_INCREMENT,
`age_min` INT(11) NULL DEFAULT '0',
`age_max` INT(11) NULL DEFAULT '0',
`value_min` INT(11) NULL DEFAULT '0',
`value_max` INT(11) NULL DEFAULT '0',
`sex` ENUM('m','w') NOT NULL DEFAULT 'm' COLLATE 'utf8_hungarian_ci',
`evaluation` ENUM('excellent','very good','good','average','weak','poor') NOT NULL DEFAULT 'average' COLLATE 'utf8_hungarian_ci',
`description` TEXT(65535) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci',
PRIMARY KEY (`evaluation_id`) USING BTREE,
INDEX `value_min_value_max` (`value_min`, `value_max`) USING BTREE,
INDEX `age_min_age_max` (`age_min`, `age_max`) USING BTREE,
INDEX `age_min_age_max_value_min_value_max` (`age_min`, `age_max`, `value_min`, `value_max`) USING BTREE
)
COLLATE='utf8_hungarian_ci'
ENGINE=InnoDB
;
CREATE TABLE `customer_information` (
`customer_information_id` INT(11) NOT NULL AUTO_INCREMENT,
`title` CHAR(50) NULL DEFAULT '' COLLATE 'utf8_hungarian_ci',
`description` TEXT(65535) NULL DEFAULT NULL COLLATE 'utf8_hungarian_ci',
`date_add` DATETIME NULL DEFAULT NULL,
`display_begin` DATETIME NULL DEFAULT NULL,
`display_end` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`customer_information_id`) USING BTREE,
INDEX `title` (`title`) USING BTREE
)
COLLATE='utf8_hungarian_ci'
ENGINE=InnoDB
;
INSERT INTO `customer_information` (`customer_information_id`, `title`, `description`, `date_add`, `display_begin`, `display_end`) VALUES (1, 'Fekvőtámasz világcsúcs', 'Világcsúcs fekvőtámasz: KJ Joseph 1 perc alatt 82 szabályos fekvőtámaszt végzett', '2020-06-01 08:00:00', '2020-06-01 08:00:00', '2023-07-01 08:00:00');
INSERT INTO `customer_information` (`customer_information_id`, `title`, `description`, `date_add`, `display_begin`, `display_end`) VALUES (2, 'Húzódszkodás csúcs', '24 órás csúcstartója Joonas Mäkipelto 5050 gyakorlattal', '2020-06-01 08:00:00', '2020-06-01 08:00:00', '2023-07-01 08:00:00');
INSERT INTO `customer_information` (`customer_information_id`, `title`, `description`, `date_add`, `display_begin`, `display_end`) VALUES (3, 'Fekvenyomás', '2015-ben a fekvenyomó világbajnokságot Smulter Fredrik finn súlyemelő 401 Kg-al nyerte', '2020-06-01 08:00:00', '2020-05-01 00:00:00', '2020-06-01 08:00:01');
DROP TABLE exercise_ages;
UPDATE configuration set config_value = "0.0.2" WHERE config_key = "db_version";

1
data/db/update_0_0_3.sql Normal file
View File

@ -0,0 +1 @@
INSERT INTO `customer` (`name`, `firstname`, `email`, `password`, `sex`, `age`, `active`, `date_add`, `date_change`, `data_policy_allowed`, `admin`) VALUES ('Dummy User', NULL, 'bosi', '$2a$10$thOc8jS750c7xe9U9Qq3GuSPs/H0Pt2Ads05yzUlyzQBIj.Rk9QCy', 'm', 40, 'N', NULL, NULL, 1, 1);

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

183
gradlew vendored Executable file
View File

@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

102
gradlew.bat vendored Normal file
View File

@ -0,0 +1,102 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

13
readme.MD Normal file
View File

@ -0,0 +1,13 @@
#aitrainer server API v0.0.5
connects the MYSQL Database
provide a RESTful API for the mobile app
##finished API
* customers
* exercise_type
* exercise
* customer_information
with automatic database update

2
settings.gradle Normal file
View File

@ -0,0 +1,2 @@
include ':src'
include ':data'

View File

@ -0,0 +1,21 @@
package com.aitrainer.api
import org.slf4j.LoggerFactory
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
@SpringBootApplication
class ApiApplication
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Override
fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(ApiApplication::class.java)
}
fun main(args: Array<String>) {
logger.info(" ---- Start aitrainer API")
SpringApplication.run(ApiApplication::class.java, *args)
}

View File

@ -0,0 +1,45 @@
package com.aitrainer.api.controller
import org.springframework.beans.factory.annotation.Value
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping
class ApplicationProperties {
@Value("\${application.version}")
private lateinit var version: String
@Value("\${spring.datasource.url}")
private lateinit var datasourceUrl: String
@Value("\${spring.datasource.username}")
private lateinit var datasourceUsername: String
@Value("\${spring.datasource.password}")
private lateinit var datasourcePassword: String
@GetMapping("/version")
fun getVersion(): String {
return this.version
}
@GetMapping("/datasourceUrl")
fun getDatasourceUrl(): String {
return this.datasourceUrl
}
@GetMapping("/datasourceUsername")
fun getDatasourceUsername(): String {
return this.datasourceUsername
}
@GetMapping("/datasourcePassword")
fun getDatasourcePassword(): String {
return this.datasourcePassword
}
}

View File

@ -0,0 +1,27 @@
package com.aitrainer.api.controller
import com.aitrainer.api.model.Configuration
import com.aitrainer.api.repository.ConfigurationRepository
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime
@RestController
class ConfigurationController ( private val configurationRepository: ConfigurationRepository) {
fun getConfiguration(key: String): Configuration =
configurationRepository.findByConfigKey(key)
fun updateConfiguration( newConfiguration: Configuration): Configuration {
val existingConfiguration: Configuration = configurationRepository.findByConfigKey(newConfiguration.configKey)
val updatedConfiguration: Configuration = existingConfiguration.copy(
configKey = newConfiguration.configKey,
configValue = newConfiguration.configValue,
//dateAdd = newConfiguration.dateAdd,
dateChange = LocalDateTime.now().toString())
configurationRepository.save(updatedConfiguration)
return existingConfiguration
}
}

View File

@ -0,0 +1,116 @@
package com.aitrainer.api.controller
import com.aitrainer.api.model.Customer
import com.aitrainer.api.model.User
import com.aitrainer.api.service.ServiceBeans
import com.aitrainer.api.repository.CustomerRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.ResponseEntity
import org.springframework.security.access.annotation.Secured
import org.springframework.web.bind.annotation.*
import javax.validation.Valid
@RestController
@RequestMapping("/api")
class CustomerController ( private val customerRepository: CustomerRepository ) {
@Autowired
var serviceBeans: ServiceBeans? = null
@Secured
@GetMapping("/customers")
fun getAllCustomers(@RequestHeader headers: HttpHeaders): List<Customer> =
customerRepository.findAll()
@Secured
@PostMapping("/customers")
fun createNewCustomer(@Valid @RequestBody customer: Customer, @RequestHeader headers: HttpHeaders): Customer =
customerRepository.save(customer)
@Secured
@GetMapping("/customers/{id}")
fun getCustomerById(@PathVariable(value = "id") customerId: Long, @RequestHeader headers: HttpHeaders): ResponseEntity<Customer> {
return customerRepository.findById(customerId).map { customer ->
ResponseEntity.ok(customer)
}.orElse(ResponseEntity.notFound().build())
}
@Secured
@GetMapping("/customers/real")
fun getRealCustomers(active: String, @RequestHeader headers: HttpHeaders): List<Customer> =
customerRepository.findByActive(active)
@Secured
@PutMapping("/customers/{id}")
fun updateCustomerById(@PathVariable(value = "id") customerId: Long,
@Valid @RequestBody newCustomer: Customer,
@RequestHeader headers: HttpHeaders): ResponseEntity<Customer> {
return customerRepository.findById(customerId).map { existingCustomer ->
val updatedCustomer: Customer = existingCustomer
.copy(name = newCustomer.name,
firstname = newCustomer.firstname,
sex = newCustomer.sex,
age = newCustomer.age)
ResponseEntity.ok().body(customerRepository.save(updatedCustomer))
}.orElse(ResponseEntity.notFound().build())
}
@PostMapping("/registration")
fun registration(@Valid @RequestBody json: String): ResponseEntity<*> {
val customer = Customer()
val newUser: User = User().fromJson(json)
with (customer) {
email = newUser.username
password = serviceBeans!!.passwordEncoder().encode(newUser.password)
}
val returnCustomer: Customer? = customerRepository.findByEmail(newUser.username).let {
if ( it == null) {
customerRepository.save(customer)
} else {
null
}
}
return if ( returnCustomer != null ) {
ResponseEntity.ok().body(returnCustomer)
} else {
ResponseEntity.badRequest().body("Customer exists")
}
}
@GetMapping("/login")
fun login(@Valid @RequestBody json: String): ResponseEntity<*> {
val customer = Customer()
val newUser: User = User().fromJson(json)
with (customer) {
email = newUser.username
password = newUser.password
}
val returnCustomer: Customer? = customerRepository.findByEmail(newUser.username).let {
if ( it == null) {
null
} else {
if (serviceBeans!!.passwordEncoder().matches(newUser.password, it.password)) {
it
} else {
null
}
}
}
return if ( returnCustomer != null ) {
ResponseEntity.ok().body(returnCustomer)
} else {
ResponseEntity.badRequest().body("Customer does not exist or the password is wrong")
}
}
}

View File

@ -0,0 +1,30 @@
package com.aitrainer.api.controller
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.repository.ConfigurationRepository
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Suppress("unused")
@Aspect
@Component
class CustomerControllerAspect {
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Before("execution(* com.aitrainer.api.controller.CustomerController.*(..))")
fun customerControllerAspect(joinPoint: JoinPoint) {
println("customer controller")
Singleton.checkDBUpdate(configurationRepository, properties)
}
}

View File

@ -0,0 +1,21 @@
package com.aitrainer.api.controller
import com.aitrainer.api.model.CustomerInformation
import com.aitrainer.api.repository.CustomerInformationRepository
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime
@RestController
@RequestMapping("/api")
class CustomerInformationController( private val customerInformationRepository: CustomerInformationRepository ) {
@GetMapping("/customer_information")
fun getCustomerInformation(): List<CustomerInformation> {
val dateTime: String = LocalDateTime.now().toString()
return customerInformationRepository.findByDisplayBeginLessThanAndDisplayEndGreaterThan(dateTime, dateTime )
}
}

View File

@ -0,0 +1,35 @@
package com.aitrainer.api.controller
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.repository.ConfigurationRepository
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.aspectj.lang.annotation.Pointcut
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Aspect
@Component
@Suppress("unused")
class CustomerInformationControllerAspect {
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Suppress("unused")
@Pointcut("execution(* com.aitrainer.api.controller.CustomerInformationController.*())")
fun customerInformationAspect() {
}
@Suppress("unused")
@Before("customerInformationAspect()")
fun dbCheckAop() {
Singleton.checkDBUpdate(configurationRepository, properties)
}
}

View File

@ -0,0 +1,102 @@
package com.aitrainer.api.controller
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.model.Configuration
import com.aitrainer.api.repository.ConfigurationRepository
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.RestController
import java.io.File
import java.sql.Connection
import java.sql.DriverManager
import java.sql.ResultSet
import java.util.Properties
@RestController
object Singleton {
private lateinit var connection: Connection
private lateinit var configurationRepository: ConfigurationRepository
private lateinit var properties: ApplicationProperties
private var initialized: Boolean = false
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
// to use the singleton functionality avoiding the db access before each request
private var dbVersion: String = ""
private var appVersion: String = ""
fun checkDBUpdate(configurationRepository: ConfigurationRepository, properties: ApplicationProperties) {
if ( dbVersion.isNotEmpty() && appVersion.isNotEmpty()) {
// no db access
//println("DB up-to-date, no DB access")
return
}
this.configurationRepository = configurationRepository
this.properties = properties
val dbConfig: Configuration = configurationRepository.findByConfigKey("db_version")
val applicationVersion: String = properties.getVersion()
this.dbVersion = dbConfig.configValue
this.appVersion = applicationVersion
if ( dbConfig.configValue != applicationVersion ) {
try {
val versionNumber: String = applicationVersion.replace(".", "_")
val fileName = "update_$versionNumber.sql"
val path = "./data/db/"
val file2Update = path+fileName
var sqlRows = ""
File(file2Update).forEachLine {
sqlRows += it
if ( sqlRows.contains(";") ) {
execSQL(sqlRows)
sqlRows = ""
}
}
this.connection.commit()
logger.info("Database has been updated to $applicationVersion" )
} catch (exception: Exception) {
logger.info("Database exception of $applicationVersion: " + exception.message )
this.connection.rollback()
}
}
}
private fun execSQL( sql: String ) {
if (! this.initialized ) {
this.getConnection()
}
with(this.connection) {
createStatement().execute(sql)
//commit()
}
}
fun execQuery( sql: String ): ResultSet {
if (! this.initialized ) {
this.getConnection()
}
return connection.createStatement().executeQuery(sql)
}
private fun getConnection(): Connection {
val connectionProps = Properties()
connectionProps["user"] = this.properties.getDatasourceUsername()
connectionProps["password"] = this.properties.getDatasourcePassword()
this.connection = DriverManager.getConnection(this.properties.getDatasourceUrl(), connectionProps)
this.connection.autoCommit = false
this.initialized = true
return this.connection
}
}

View File

@ -0,0 +1,43 @@
package com.aitrainer.api.controller
import com.aitrainer.api.model.Exercises
import com.aitrainer.api.repository.ExercisesRepository
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import javax.validation.Valid
@RestController
@RequestMapping("/api")
class ExerciseController(private val exercisesRepository: ExercisesRepository) {
@GetMapping("/exercises/{id}")
fun getExerciseById(@PathVariable(value = "id") exerciseId: Long): ResponseEntity<Exercises> {
return exercisesRepository.findById(exerciseId).map { exercise ->
ResponseEntity.ok(exercise)
}.orElse(ResponseEntity.notFound().build())
}
@GetMapping("/exercises/customer/{id}")
fun getAllExersicesByCustomerId(@PathVariable( value = "id" ) customerId: Long? ): List<Exercises> =
exercisesRepository.getAllByCustomerId(customerId)
@PostMapping("/exercises")
fun createNewExercise(@Valid @RequestBody exercise: Exercises): Exercises {
return exercisesRepository.save(exercise)
}
@PutMapping("/exercises/{id}")
fun updateExerciseById(@PathVariable(value = "id") exerciseId: Long,
@Valid @RequestBody newExercises: Exercises): ResponseEntity<Exercises> {
return exercisesRepository.findById(exerciseId).map { existingExercises ->
val updatedExercises: Exercises = existingExercises.copy(
exerciseTypeId = newExercises.exerciseTypeId,
customerId = newExercises.customerId,
dateAdd = newExercises.dateAdd,
quantity = newExercises.quantity,
restTime = newExercises.restTime
)
ResponseEntity.ok().body(exercisesRepository.save(updatedExercises))
}.orElse(ResponseEntity.notFound().build())
}
}

View File

@ -0,0 +1,35 @@
package com.aitrainer.api.controller
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.repository.ConfigurationRepository
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.aspectj.lang.annotation.Pointcut
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Component
@Suppress("unused")
@Aspect
class ExerciseControllerAspect {
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Suppress("unused")
@Pointcut("execution(* com.aitrainer.api.controller.ExerciseController.*())")
fun exerciseControllerAspect() {
}
@Before("exerciseControllerAspect()")
fun loggingAop() {
Singleton.checkDBUpdate(configurationRepository, properties)
}
}

View File

@ -0,0 +1,60 @@
package com.aitrainer.api.controller
import com.aitrainer.api.model.ExerciseType
import com.aitrainer.api.repository.ExerciseTypeRepository
import org.slf4j.LoggerFactory
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import javax.validation.Valid
@RestController
@RequestMapping("/api")
class ExerciseTypeController ( private val exerciseTypeRepository: ExerciseTypeRepository ) {
private val logger = LoggerFactory.getLogger(javaClass)
@GetMapping("/exercise_type")
fun getAllExerciseType(): List<ExerciseType> {
val list: List<ExerciseType> = exerciseTypeRepository.findAll()
logger.info(" -- Get All exercise types..")
return list
}
@PostMapping("/exercise_type")
fun createNewExerciseType(@Valid @RequestBody exerciseType: ExerciseType): ExerciseType {
logger.info("Create new exercise type: $exerciseType")
return exerciseTypeRepository.save(exerciseType)
}
@GetMapping("/exercise_type/{id}")
fun getExerciseTypeById(@PathVariable(value = "id") exerciseTypeId: Long): ResponseEntity<ExerciseType> {
logger.info("Get exercise type by id: $exerciseTypeId")
return exerciseTypeRepository.findById(exerciseTypeId).map { exerciseType ->
ResponseEntity.ok(exerciseType)
}.orElse(ResponseEntity.notFound().build())
}
/*
@GetMapping("/exercise_type/name/{name}")
fun getExerciseTypeByName(@PathVariable(value = "name") name: String): ResponseEntity<ExerciseType> {
return exerciseTypeRepository.findByName(name).map { exerciseType ->
ResponseEntity.ok(exerciseType)
}.orElse(ResponseEntity.notFound().build())
}*/
@PostMapping("/exercise_type/{id}")
fun updateExerciseTypesById(@PathVariable(value = "id") exerciseTypeId: Long,
@Valid @RequestBody newExerciseType: ExerciseType): ResponseEntity<ExerciseType> {
logger.info("Update exercise type by id: $exerciseTypeId with object $newExerciseType")
return exerciseTypeRepository.findById(exerciseTypeId).map { existingExerciseType ->
val updatedExerciseType: ExerciseType = existingExerciseType
.copy(name = newExerciseType.name,
description = newExerciseType.description,
video = newExerciseType.video)
ResponseEntity.ok().body(exerciseTypeRepository.save(updatedExerciseType))
}.orElse(ResponseEntity.notFound().build())
}
}

View File

@ -0,0 +1,33 @@
package com.aitrainer.api.controller
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.repository.ConfigurationRepository
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.aspectj.lang.annotation.Pointcut
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Suppress("unused")
@Aspect
@Component
class ExerciseTypeControllerAspect {
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Suppress("unused")
@Pointcut("execution(* com.aitrainer.api.controller.ExerciseTypeController.*())")
fun exerciseTypeControllerAspect() {
}
@Before("exerciseTypeControllerAspect()")
fun loggingAop() {
Singleton.checkDBUpdate(configurationRepository, properties)
}
}

View File

@ -0,0 +1,20 @@
package com.aitrainer.api.model
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.NotBlank
@Entity
data class Configuration (
@get: NotBlank var configKey: String = "",
@get: NotBlank var configValue: String = "",
var dateAdd: String,
var dateChange: String = "",
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val configuration_id: Long = 0
)

View File

@ -0,0 +1,24 @@
package com.aitrainer.api.model
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
@Entity
data class Customer (
var name: String = "",
var firstname: String = "",
var email: String = "",
var age: Int = 0,
var sex: String = "m",
var active: String = "N",
var dateAdd: String? = null,
var dateChange: String? = null,
var dataPolicyAllowed: Int = 0,
var admin: Int = 0,
var password: String = "",
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val customer_id: Long = 0
)

View File

@ -0,0 +1,21 @@
package com.aitrainer.api.model
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.NotBlank
@Entity
class CustomerInformation (
@get: NotBlank var title: String = "",
var description: String = "",
var dateAdd: String? = null,
var displayBegin: String? = null,
var displayEnd: String? = null,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val customerInformationId: Long = 0
)

View File

@ -0,0 +1,21 @@
package com.aitrainer.api.model
import org.hibernate.type.BinaryType
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.NotBlank
import javax.validation.constraints.Null
@Entity
data class ExerciseType (
@get: NotBlank var name: String = "",
@get: NotBlank var description: String = "",
@get: Null var video: BinaryType?,
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val exerciseTypeId: Long = 0
)

View File

@ -0,0 +1,21 @@
package com.aitrainer.api.model
import org.springframework.lang.NonNull
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.Null
@Entity
data class Exercises (
@get: NonNull var exerciseTypeId: Long = 0,
@get: NonNull var customerId: Long = 0,
@get: NonNull var dateAdd: String? = null,
@get: NonNull var quantity: Int = 0,
@get: Null var restTime: Int?, // in seconds
@get: NonNull var unit: String? = null,
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val exerciseId: Long = 0
)

View File

@ -0,0 +1,15 @@
package com.aitrainer.api.model
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User (
var username: String = "",
var password: String = ""
) {
@OptIn(UnstableDefault::class)
fun fromJson(json: String): User {
return Json.parse(serializer(), json)
}
}

View File

@ -0,0 +1,10 @@
package com.aitrainer.api.repository
import com.aitrainer.api.model.Configuration
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface ConfigurationRepository : JpaRepository<Configuration, Long> {
fun findByConfigKey( key: String ):Configuration
}

View File

@ -0,0 +1,11 @@
package com.aitrainer.api.repository
import com.aitrainer.api.model.CustomerInformation
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface CustomerInformationRepository: JpaRepository<CustomerInformation, Long> {
fun findByDisplayBeginLessThanAndDisplayEndGreaterThan( dateTimeBegin: String, dateTimeEnd: String ):
List<CustomerInformation>
}

View File

@ -0,0 +1,12 @@
package com.aitrainer.api.repository
import com.aitrainer.api.model.Customer
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface CustomerRepository : JpaRepository<Customer, Long> {
fun findByActive( active: String? ): List<Customer>
fun findByEmail(email: String?): Customer?
}

View File

@ -0,0 +1,12 @@
package com.aitrainer.api.repository
import com.aitrainer.api.model.ExerciseType
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface ExerciseTypeRepository : JpaRepository<ExerciseType, Long>{
fun findByName(name: String): ExerciseType
}

View File

@ -0,0 +1,10 @@
package com.aitrainer.api.repository
import com.aitrainer.api.model.Exercises
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface ExercisesRepository : JpaRepository<Exercises, Long> {
fun getAllByCustomerId( customerId: Long? ):List<Exercises>
}

View File

@ -0,0 +1,31 @@
package com.aitrainer.api.security
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.controller.ApplicationProperties
import com.aitrainer.api.controller.Singleton
import com.aitrainer.api.repository.ConfigurationRepository
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Suppress("unused")
@Aspect
@Component
class AuthenticationControllerAspect {
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Before("execution(* com.aitrainer.api.security.JwtAuthenticationController.*(..))")
fun customerControllerAspect(joinPoint: JoinPoint) {
println("auth controller join")
Singleton.checkDBUpdate(configurationRepository, properties)
}
}

View File

@ -0,0 +1,49 @@
package com.aitrainer.api.security
import com.aitrainer.api.service.UserDetailsServiceImpl
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.web.bind.annotation.*
import org.springframework.stereotype.Component
@Component
@RestController
//@CrossOrigin
@RequestMapping("/api")
class JwtAuthenticationController {
@Autowired
private val authenticationManager: AuthenticationManager? = null
@Autowired
private val jwtTokenUtil: JwtTokenUtil? = null
@Autowired
private val jwtUserDetailsService: UserDetailsServiceImpl? = null
@PostMapping("/authenticate")
fun generateAuthenticationToken(@RequestBody authenticationRequest: JwtRequest): ResponseEntity<*> {
authenticate(authenticationRequest.username!!, authenticationRequest.password!!)
val userDetails = jwtUserDetailsService
?.loadUserByUsername(authenticationRequest.username)
val token: String = jwtTokenUtil!!.generateToken(userDetails!!)
return ResponseEntity.ok<Any>(JwtResponse(token))
}
private fun authenticate(username: String, password: String) {
try {
authenticationManager!!.authenticate(UsernamePasswordAuthenticationToken(username, password))
} catch (e: DisabledException) {
throw Exception("USER_DISABLED", e)
} catch (e: BadCredentialsException) {
throw Exception("INVALID_CREDENTIALS", e)
}
}
}

View File

@ -0,0 +1,23 @@
package com.aitrainer.api.security
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.stereotype.Component
import java.io.IOException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.io.Serializable
import org.springframework.security.core.AuthenticationException
@Component
class JwtAuthenticationEntryPoint : AuthenticationEntryPoint, Serializable {
@Throws(IOException::class)
override fun commence(request: HttpServletRequest?, response: HttpServletResponse,
authException: AuthenticationException?) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized")
}
companion object {
private const val serialVersionUID = -7858869558953243875L
}
}

View File

@ -0,0 +1,19 @@
package com.aitrainer.api.security
import java.io.Serializable
class JwtRequest : Serializable {
var username: String? = null
var password: String? = null
//default constructor for JSON Parsing
constructor(username: String?, password: String?) {
this.username = username
this.password = password
}
companion object {
private const val serialVersionUID = 5926468583005150707L
}
}

View File

@ -0,0 +1,77 @@
package com.aitrainer.api.security
import com.aitrainer.api.service.UserDetailsServiceImpl
import io.jsonwebtoken.ExpiredJwtException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import java.io.IOException
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@Component
class JwtRequestFilter : OncePerRequestFilter() {
@Autowired
private val jwtUserDetailsService: UserDetailsServiceImpl? = null
@Autowired
private val jwtTokenUtil: JwtTokenUtil? = null
//@Autowired
//private lateinit var authenticationController: JwtAuthenticationController
@Throws(ServletException::class, IOException::class)
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
val requestTokenHeader = request.getHeader("Authorization")
var username: String? = null
var jwtToken: String? = null
// JWT Token is in the form "Bearer token". Remove Bearer word and get only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer")) {
jwtToken = requestTokenHeader.substring(7)
try {
username = jwtTokenUtil!!.getUsernameFromToken(jwtToken)
} catch (e: IllegalArgumentException) {
println("Unable to get JWT Token")
} catch (e: ExpiredJwtException) {
println("JWT Token has expired")
}
} else if (requestTokenHeader != null && requestTokenHeader.equals("1") ) {
logger.warn("Authenticate")
//val credentials: User = ObjectMapper().readValue(request.inputStream, User::class.java)
} else {
logger.warn("JWT Token does not begin with Bearer String")
}
//Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().authentication == null) {
val userDetails: UserDetails = jwtUserDetailsService!!.loadUserByUsername(username)
// if token is valid configure Spring Security to manually set authentication
if (jwtTokenUtil!!.validateToken(jwtToken!!, userDetails)) {
val usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.authorities)
usernamePasswordAuthenticationToken.details = WebAuthenticationDetailsSource().buildDetails(request)
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the Spring Security Configurations successfully.
SecurityContextHolder.getContext().authentication = usernamePasswordAuthenticationToken
}
}
chain.doFilter(request, response)
}
/*private fun readUserCredentials(request: HttpServletRequest): UserCredentials? {
return try {
ObjectMapper().readValue(request.inputStream, UserCredentials::class.java)
} catch (ioe: IOException) {
throw BadCredentialsException("Invalid request", ioe)
}
}*/
}

View File

@ -0,0 +1,12 @@
package com.aitrainer.api.security
import java.io.Serializable
class JwtResponse(val token: String) : Serializable {
companion object {
private const val serialVersionUID = -8091879091924046844L
}
}

View File

@ -0,0 +1,65 @@
package com.aitrainer.api.security
import com.aitrainer.api.service.ServiceBeans
import com.aitrainer.api.service.UserDetailsServiceImpl
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
@Configuration
@EnableWebSecurity
class JwtSecurityConfig : WebSecurityConfigurerAdapter() {
@Autowired
private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint? = null
@Autowired
private val jwtUserDetailsService: UserDetailsServiceImpl? = null
@Autowired
private val jwtRequestFilter: JwtRequestFilter? = null
@Autowired
private val serviceBeans: ServiceBeans? = null
override fun configure(auth: AuthenticationManagerBuilder?) {
auth!!.userDetailsService(jwtUserDetailsService).passwordEncoder(serviceBeans!!.passwordEncoder())
}
@Bean
@Throws(Exception::class)
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
@Throws(Exception::class)
override fun configure(httpSecurity: HttpSecurity) {
// We don't need CSRF for this example
httpSecurity.
csrf().disable().
// dont authenticate this particular request
authorizeRequests().antMatchers("/api/authenticate").permitAll().
// all other requests need to be authenticated
anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().
// Add a filter to validate the tokens with every request
//addFilterAt(JwtAuthenticationFilter(authenticationManagerBean()), UsernamePasswordAuthenticationFilter::class.java).
addFilterAfter(jwtRequestFilter, UsernamePasswordAuthenticationFilter::class.java).
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
}

View File

@ -0,0 +1,67 @@
package com.aitrainer.api.security
import org.springframework.beans.factory.annotation.Value
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component
import java.util.*
import java.io.Serializable
import io.jsonwebtoken.Claims
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
@Component
class JwtTokenUtil : Serializable {
@Value("\${jwt.secret}")
private val secret: String? = null
fun getUsernameFromToken(token: String?): String {
return getClaimFromToken(token, Claims::getSubject)
}
fun getIssuedAtDateFromToken(token: String?): Date {
return getClaimFromToken<Date>(token, Claims::getIssuedAt)
}
fun getExpirationDateFromToken(token: String?): Date {
return getClaimFromToken<Date>(token, Claims::getExpiration)
}
fun <T> getClaimFromToken( token: String?, claimsResolver: ( Claims.()-> T ) ): T {
val claims: Claims = getAllClaimsFromToken(token)
return claims.claimsResolver()
}
private fun getAllClaimsFromToken(token: String?): Claims {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).body
}
private fun isTokenExpired(token: String): Boolean {
val expiration: Date = getExpirationDateFromToken(token)
return expiration.before(Date())
}
fun generateToken(userDetails: UserDetails): String {
val claims: Map<String, Any> = HashMap()
return doGenerateToken(claims, userDetails.username)
}
private fun doGenerateToken(claims: Map<String, Any>, subject: String): String {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(Date(System.currentTimeMillis()))
.setExpiration(Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000)).signWith(SignatureAlgorithm.HS512, secret).compact()
}
fun canTokenBeRefreshed(token: String): Boolean {
return !isTokenExpired(token)
}
fun validateToken(token: String, userDetails: UserDetails): Boolean {
val username = getUsernameFromToken(token)
return username == userDetails.username && !isTokenExpired(token)
}
companion object {
private const val serialVersionUID = -2550185165626007488L
const val JWT_TOKEN_VALIDITY = 5 * 60 * 60.toLong()
}
}

View File

@ -0,0 +1,10 @@
package com.aitrainer.api.service
import com.aitrainer.api.model.Customer
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
interface CustomerService {
@Query("FROM customer WHERE active = :active ")
fun findByActive(@Param("active") active: String? ): List<Customer>
}

View File

@ -0,0 +1,10 @@
package com.aitrainer.api.service
import com.aitrainer.api.model.Exercises
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
interface ExerciseService {
@Query("FROM exercises WHERE customer_id = :customerId")
fun findAllByCustomerId( @Param("customerId") customerId: Long? ): List<Exercises>
}

View File

@ -0,0 +1,19 @@
package com.aitrainer.api.service
import org.springframework.context.annotation.Bean
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Component
/*
Commonly used Beans
*/
@Component
class ServiceBeans {
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}

View File

@ -0,0 +1,34 @@
package com.aitrainer.api.service
import com.aitrainer.api.model.Customer
import com.aitrainer.api.repository.CustomerRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import kotlin.collections.HashSet
@Service
class UserDetailsServiceImpl: UserDetailsService {
@Autowired
private lateinit var customerRepository: CustomerRepository
@Override
@Transactional(readOnly = true)
override fun loadUserByUsername(username: String?): UserDetails {
val customer: Customer? = customerRepository.findByEmail(username)
val grantedAuthorities = HashSet<GrantedAuthority>()
grantedAuthorities.add(SimpleGrantedAuthority("user"))
if (customer != null) {
return User(customer.email, customer.password, grantedAuthorities)
} else {throw Exception("User does not exist")}
}
}

View File

@ -0,0 +1,13 @@
spring.profiles.active=dev
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
#spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.username = aitrainer
spring.datasource.password = andio2009
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

View File

@ -0,0 +1,13 @@
spring.profiles.active=prod
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
#spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&allowMultiQueries=true
spring.datasource.username = aitrainer
spring.datasource.password = andio2009
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

View File

@ -0,0 +1,13 @@
spring.profiles.active=test
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
#spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.url = jdbc:mysql://mysql:3306/aitrainer?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&allowMultiQueries=true
spring.datasource.username = root
spring.datasource.password = andio2009
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

View File

@ -0,0 +1,21 @@
spring.profiles.active=dev,test,prod
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
#spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.url = jdbc:mysql://localhost:3306/aitrainer?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.username = aitrainer
spring.datasource.password = andio2009
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
logging.config=classpath:logback-spring.xml
logging.file=logs
# if the database structure has been changed, increment this version number
application.version=0.0.3
jwt.secret=aitrainer

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<property resource="application.properties"/>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logging.file}/aitrainer.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logging.file}/aitrainer.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%thread] [%logger:%line] %msg%n
</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%thread] [%logger:%line] %msg%n
</pattern>
</encoder>
</appender>
<!-- <logger name="org.springframework" level="DEBUG" /> -->
<logger name="com.aitrainer" level="INFO" />
<logger name="org.hibernate" level="INFO" />
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>

View File

@ -0,0 +1,34 @@
package com.aitrainer.api.test
import com.aitrainer.api.controller.ApplicationProperties
import com.aitrainer.api.controller.Singleton
import com.aitrainer.api.repository.ConfigurationRepository
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import java.sql.ResultSet
import kotlin.test.assertEquals
@SpringBootTest
class ApplicationStartTest {
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Test
fun testDBCheck() {
Singleton.checkDBUpdate(this.configurationRepository, this.properties)
var foundTable = false
val rs: ResultSet = Singleton.execQuery("Show tables;")
while ( rs.next() ) {
if ( rs.getString("tables_in_aitrainer") == "customer_information" ) {
foundTable = true
}
}
assertEquals(foundTable, true)
}
}

View File

@ -0,0 +1,25 @@
package com.aitrainer.api.test
import com.aitrainer.api.security.JwtAuthenticationController
import com.aitrainer.api.security.JwtRequest
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import kotlin.test.assertEquals
@SpringBootTest
class AuthenticationTest {
@Autowired
private lateinit var authController: JwtAuthenticationController
@Test
fun testAuthentication() {
val response: ResponseEntity<*>
val jwtRequest = JwtRequest("bosi", "andio2009")
response = authController.generateAuthenticationToken(jwtRequest)
assertEquals(response.statusCode, HttpStatus.OK)
}
}

View File

@ -0,0 +1,31 @@
package com.aitrainer.api.test
import com.aitrainer.api.controller.ConfigurationController
import com.aitrainer.api.model.Configuration
import com.aitrainer.api.repository.ConfigurationRepository
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import kotlin.test.assertEquals
@SpringBootTest
class ConfigurationTest {
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
private lateinit var configurationController: ConfigurationController
@Test
fun testUpdateConfig() {
val config: Configuration = configurationRepository.findByConfigKey("db_version")
config.configValue = "0.0.2"
configurationController = ConfigurationController(configurationRepository)
val updatedConfig: Configuration = configurationController.updateConfiguration(config)
assertEquals(updatedConfig.configValue, "0.0.2")
val foundConfig: Configuration = configurationRepository.findByConfigKey("db_version")
assertEquals(foundConfig.configValue, "0.0.2")
}
}

View File

@ -0,0 +1,24 @@
package com.aitrainer.api.test
import com.aitrainer.api.model.CustomerInformation
import com.aitrainer.api.repository.CustomerInformationRepository
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import kotlin.test.assertEquals
@SpringBootTest
class CustomerInformationTest {
@Autowired
private lateinit var customerInformationRepository: CustomerInformationRepository
@Test
fun getActiveCustomerInformation() {
val dateTime = "2020-06-01 09:00:00"
val info: List<CustomerInformation> = this.customerInformationRepository.
findByDisplayBeginLessThanAndDisplayEndGreaterThan(dateTime, dateTime )
assertEquals(info.size, 2)
assertEquals(info.first().title, "Fekvőtámasz világcsúcs")
}
}

View File

@ -0,0 +1,122 @@
package com.aitrainer.api.test
import com.aitrainer.api.controller.CustomerController
import com.aitrainer.api.model.Customer
import com.aitrainer.api.model.User
import com.aitrainer.api.repository.CustomerRepository
import com.aitrainer.api.service.ServiceBeans
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CustomerTests {
@Autowired
private var serviceBean: ServiceBeans? = null
@BeforeAll
fun init() {
if ( serviceBean == null ) { serviceBean = ServiceBeans() }
}
@Autowired
private lateinit var customerRepository: CustomerRepository
private var insertedId: Long? = null
@Test
fun testGet() {
val id: Long = 7
val customer: Customer = customerRepository.findById( id ).orElse(null)
assertEquals( customer.name, "Átlag 18 éves fiú")
}
@Test
fun testInsert() {
val newCustomer = Customer("Bossanyi", "Tibor", "", 48, "m")
val savedCustomer: Customer = customerRepository.save(newCustomer)
assertEquals(savedCustomer.age, 48)
this.insertedId = savedCustomer.customer_id
val customer: Customer = customerRepository.findById( savedCustomer.customer_id ).orElse(null)
assertEquals( customer.firstname, "Tibor")
this.testUpdate(savedCustomer.customer_id)
}
fun testUpdate( customerId: Long ) {
val id: Long? = customerId
assertNotNull(id)
val updatedCustomer: Customer = customerRepository.findById( id ).orElse(null)
assertNotNull(updatedCustomer)
updatedCustomer.firstname ="Tiborka"
val customer: Customer = customerRepository.save( updatedCustomer )
assertEquals( customer.firstname, "Tiborka")
customerRepository.delete(updatedCustomer)
}
@Test
fun testRegistration() {
val json = "{\"username\":\"bosi@example.com\",\"password\":\"94385\"}"
val user: User = User().fromJson(json)
assertEquals(user.username, "bosi@example.com")
val customer = Customer()
with(customer) {
email = user.username
password = user.password
}
val customerController = CustomerController(customerRepository)
customerController.serviceBeans = serviceBean
var response: ResponseEntity<*> = customerController.registration(json)
val newCustomer: Customer? = response.body as Customer
assertEquals(response.statusCode, HttpStatus.OK)
val json2 = "{\"username\":\"bosi@example.com\",\"password\":\"934345\"}"
response = customerController.registration(json2)
assertEquals(response.statusCode, HttpStatus.BAD_REQUEST)
if ( newCustomer != null) {
customerRepository.delete(newCustomer)
}
}
@Test fun testLogin() {
val json = "{\"username\":\"bosi2@example.com\",\"password\":\"94333385\"}"
val user: User = User().fromJson(json)
val customer = Customer()
with(customer) {
email = user.username
password = user.password
}
val customerController = CustomerController(customerRepository)
customerController.serviceBeans = serviceBean
var response: ResponseEntity<*> = customerController.registration(json)
val newCustomer: Customer? = response.body as Customer
assertEquals(response.statusCode, HttpStatus.OK)
response = customerController.login(json)
val loginedCustomer: Customer? = response.body as Customer
assertEquals(response.statusCode, HttpStatus.OK)
if ( loginedCustomer != null ) {
assertEquals(loginedCustomer.email, ("bosi2@example.com") )
} else {
assert(true)
}
if ( newCustomer != null) {
customerRepository.delete(newCustomer)
}
}
}

View File

@ -0,0 +1,44 @@
package com.aitrainer.api.test
import com.aitrainer.api.model.Exercises
import com.aitrainer.api.repository.ExercisesRepository
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@SpringBootTest
class ExerciseTest {
@Autowired
private lateinit var exerciseRepository: ExercisesRepository
@Test
fun testGet() {
var id: Long = 1
val exercises: List<Exercises> = exerciseRepository.getAllByCustomerId( id )
assertEquals( exercises[0].quantity, 12)
id = 100000
val exercises2: List<Exercises> = exerciseRepository.getAllByCustomerId( id )
assertEquals( exercises2.size, 0)
}
@Test
fun testInsert() {
val exercise = Exercises(
exerciseTypeId = 3,
customerId = 11,
quantity = 100,
dateAdd = "2020-05-13 04:32:00",
unit = "repeat",
restTime = null
)
val exerciseNew = exerciseRepository.save(exercise)
assertTrue(exerciseNew.exerciseId > 2)
exerciseRepository.delete(exercise)
}
}

View File

@ -0,0 +1,49 @@
package com.aitrainer.api.test
import com.aitrainer.api.model.ExerciseType
import com.aitrainer.api.repository.ExerciseTypeRepository
import org.junit.jupiter.api.Test
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import kotlin.test.assertEquals
@SpringBootTest
class ExerciseTypeTest {
private val logger = LoggerFactory.getLogger(javaClass)
@Autowired
private lateinit var exerciseTypeRepository: ExerciseTypeRepository
private var insertedId: Long = 0
@Test
fun testGet() {
val id: Long = 7
val extype: ExerciseType = exerciseTypeRepository.findById(id).orElse(null)
assertEquals(extype.name, "4x10m-es ingafutás")
}
@Test
fun testGetAll() {
val exerciseTypes: List<ExerciseType> = exerciseTypeRepository.findAll()
assertEquals(exerciseTypes[0].exerciseTypeId, 1)
assertEquals(exerciseTypes[0].name, "Melső fekvőtámasz 1 perc")
}
@Test
fun testInsert(){
logger.info("Add 'Húzodzkodás 2")
val newEx = ExerciseType( "Húzodzkodás 2", " A legtöbb húzodszkodást 24 óra alatt John Ort érte el 7600-al 2016-ban. ", null )
val savedEx: ExerciseType = exerciseTypeRepository.save(newEx)
assertEquals(savedEx.name, "Húzodzkodás 2")
this.insertedId = savedEx.exerciseTypeId
logger.info("Find 'Húzodzkodás 2")
val extype: ExerciseType = exerciseTypeRepository.findById( savedEx.exerciseTypeId ).orElse(null)
assertEquals( extype.name, "Húzodzkodás 2")
logger.info("Delete 'Húzodzkodás 2")
exerciseTypeRepository.delete(extype)
}
}

View File

@ -0,0 +1,27 @@
package com.aitrainer.api.test
import com.aitrainer.api.controller.ApplicationProperties
import org.springframework.boot.test.context.SpringBootTest
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import kotlin.test.assertEquals
@SpringBootTest
class PropertiesTest {
@Autowired
private lateinit var properties: ApplicationProperties
@Test
fun testProperties() {
val version: String = properties.getVersion()
assertEquals(version, "0.0.2")
}
@Test
fun testDatasourceUrl() {
val url: String = properties.getDatasourceUrl()
assertEquals(url, "jdbc:mysql://localhost:3306/aitrainer?serverTimezone=CET&useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true")
}
}