chore: setup
Some checks failed
Quality Check / Validate OAS (push) Successful in 37s
Build Application / build (push) Successful in 1m5s
Build Application / build-docker (push) Failing after 9s
Build Application / release (push) Has been skipped
Quality Check / Linting (push) Successful in 56s
Quality Check / Testing (push) Successful in 44s
Quality Check / Static Analysis (push) Successful in 1m8s
Some checks failed
Quality Check / Validate OAS (push) Successful in 37s
Build Application / build (push) Successful in 1m5s
Build Application / build-docker (push) Failing after 9s
Build Application / release (push) Has been skipped
Quality Check / Linting (push) Successful in 56s
Quality Check / Testing (push) Successful in 44s
Quality Check / Static Analysis (push) Successful in 1m8s
This commit is contained in:
commit
d2ef6fadef
43 changed files with 1222 additions and 0 deletions
29
.forgejo/pull_request_template.yml
Normal file
29
.forgejo/pull_request_template.yml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
name: Feature
|
||||||
|
title: '[Feature]: '
|
||||||
|
about: 'Vorlage Für ein Feature Ticket'
|
||||||
|
ref: 'trunk'
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: ticket
|
||||||
|
attributes:
|
||||||
|
label: Ticket
|
||||||
|
description: Für Welches Ticket ist diese Pull Request?
|
||||||
|
placeholder: TD-1
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: beschreibung
|
||||||
|
attributes:
|
||||||
|
label: Beschreibung
|
||||||
|
description: Was hast du genau gemacht in diesem Ticket?
|
||||||
|
placeholder: ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: more
|
||||||
|
attributes:
|
||||||
|
label: Weitere Infos
|
||||||
|
description: Gibt es noch etwas das ich wissen muss um das Ticket zu Reviewn?
|
||||||
|
placeholder: ...
|
||||||
|
validations:
|
||||||
|
required: false
|
7
.forgejo/workflows/Dockerfile
Normal file
7
.forgejo/workflows/Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
FROM amazoncorretto:21-alpine
|
||||||
|
|
||||||
|
ARG VERSION
|
||||||
|
|
||||||
|
ADD tower_defence_server-$VERSION.jar tower_defence_server.jar
|
||||||
|
|
||||||
|
ENTRYPOINT ["java","-jar","/tower_defence_server.jar"]
|
92
.forgejo/workflows/build.yml
Normal file
92
.forgejo/workflows/build.yml
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
name: Build Application
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?'
|
||||||
|
- "v*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: stable
|
||||||
|
container:
|
||||||
|
image: git.euph.dev/actions/runner-java-21:latest
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
- name: "Prepare Gradle"
|
||||||
|
run: gradle clean
|
||||||
|
- name: "Build Jar"
|
||||||
|
run: gradle bootJar -Pversion=${{ github.ref_name }}
|
||||||
|
- name: Upload Jar as Artifact
|
||||||
|
uses: "https://git.euph.dev/actions/upload-artifact@v3"
|
||||||
|
with:
|
||||||
|
name: tower_defence_server.jar
|
||||||
|
path: build/libs/Tower-Defence-Server-${{ github.ref_name }}.jar
|
||||||
|
- name: "Stop Gradle"
|
||||||
|
run: gradle --stop
|
||||||
|
|
||||||
|
build-docker:
|
||||||
|
runs-on: docker
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
|
- name: Download artifact from previous job
|
||||||
|
uses: "https://git.euph.dev/actions/download-artifact@v3"
|
||||||
|
with:
|
||||||
|
name: tower_defence_server.jar
|
||||||
|
path: .forgejo/workflows/
|
||||||
|
- name: Login to Registry
|
||||||
|
uses: "https://git.euph.dev/actions/docker-login@v3"
|
||||||
|
with:
|
||||||
|
registry: git.euph.dev
|
||||||
|
username: ${{ secrets.DEPLOY_USER }}
|
||||||
|
password: ${{ secrets.DEPLOY_SECRET }}
|
||||||
|
- name: Build and push Web Image
|
||||||
|
uses: "https://git.euph.dev/actions/docker-build-push@v5"
|
||||||
|
with:
|
||||||
|
context: ".forgejo/workflows/"
|
||||||
|
push: true
|
||||||
|
build-args: VERSION=${{ github.ref_name }}
|
||||||
|
tags: |
|
||||||
|
git.euph.dev/towerdefence/server:${{ github.ref_name }}
|
||||||
|
${{ contains(github.ref_name, 'rc') == false && 'git.euph.dev/towerdefence/server:latest' || '' }}
|
||||||
|
|
||||||
|
release:
|
||||||
|
runs-on: stable
|
||||||
|
container:
|
||||||
|
image: git.euph.dev/actions/runner-basic:latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
- build-docker
|
||||||
|
steps:
|
||||||
|
- name: Download Server Jar
|
||||||
|
uses: "https://git.euph.dev/actions/download-artifact@v3"
|
||||||
|
with:
|
||||||
|
name: tower_defence_server.jar
|
||||||
|
path: release
|
||||||
|
- name: Create Release
|
||||||
|
uses: "https://git.euph.dev/actions/release@v2"
|
||||||
|
with:
|
||||||
|
direction: upload
|
||||||
|
tag: ${{ github.ref_name }}
|
||||||
|
token: ${{ secrets.DEPLOY_TOKEN }}
|
||||||
|
prerelease: ${{ contains( github.ref_name, "rc") }}
|
||||||
|
release-dir: release
|
||||||
|
release-notes: |
|
||||||
|
# Tower Defence - Server ${{ github.ref_name }}
|
||||||
|
|
||||||
|
Read the [Documentation](https://git.euph.dev/TowerDefence/Dokumentation/wiki/Server/Config) to see how to setup the server.
|
||||||
|
|
||||||
|
|
||||||
|
|
108
.forgejo/workflows/qs.yml
Normal file
108
.forgejo/workflows/qs.yml
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
name: "Quality Check"
|
||||||
|
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
oas:
|
||||||
|
name: "Validate OAS"
|
||||||
|
runs-on: stable
|
||||||
|
container:
|
||||||
|
image: "git.euph.dev/actions/runner-java-21:latest"
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
- name: "Prepare Gradle"
|
||||||
|
run: gradle clean
|
||||||
|
- name: "Validate OAS Spec"
|
||||||
|
run: gradle validateSwagger
|
||||||
|
- name: "Stop Gradle"
|
||||||
|
run: gradle --stop
|
||||||
|
|
||||||
|
linting:
|
||||||
|
name: "Linting"
|
||||||
|
runs-on: stable
|
||||||
|
container:
|
||||||
|
image: "git.euph.dev/actions/runner-java-21:latest"
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
- name: "Prepare Gradle"
|
||||||
|
run: gradle clean
|
||||||
|
- name: "Generate OAS Boilerplate"
|
||||||
|
run: gradle generateSwaggerCode
|
||||||
|
- name: "Linting Main"
|
||||||
|
run: gradle checkstyleMain
|
||||||
|
- name: "Linting Test"
|
||||||
|
run: gradle checkstyleTest
|
||||||
|
- name: "Stop Gradle"
|
||||||
|
run: gradle --stop
|
||||||
|
|
||||||
|
static:
|
||||||
|
name: "Static Analysis"
|
||||||
|
runs-on: stable
|
||||||
|
container:
|
||||||
|
image: "git.euph.dev/actions/runner-java-21:latest"
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
- name: "Prepare Gradle"
|
||||||
|
run: gradle clean
|
||||||
|
- name: "Generate OAS Boilerplate"
|
||||||
|
run: gradle generateSwaggerCode
|
||||||
|
- name: "Static Analysis Main"
|
||||||
|
run: gradle spotbugsMain
|
||||||
|
- name: "Static Analysis Test"
|
||||||
|
run: gradle spotbugsTest
|
||||||
|
- name: "Stop Gradle"
|
||||||
|
run: gradle --stop
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: "Testing"
|
||||||
|
runs-on: stable
|
||||||
|
container:
|
||||||
|
image: "git.euph.dev/actions/runner-java-21:latest"
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
- name: "Prepare Gradle"
|
||||||
|
run: gradle clean
|
||||||
|
- name: "Generate OAS Boilerplate"
|
||||||
|
run: gradle generateSwaggerCode
|
||||||
|
- name: "Run Tests"
|
||||||
|
run: gradle test
|
||||||
|
- name: "Stop Gradle"
|
||||||
|
run: gradle --stop
|
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/gradlew text eol=lf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.jar binary
|
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
.gradle
|
||||||
|
gradlew
|
||||||
|
gradlew.bat
|
||||||
|
build/
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
out/
|
||||||
|
!**/src/main/**/out/
|
||||||
|
!**/src/test/**/out/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
11
.run/Check.run.xml
Normal file
11
.run/Check.run.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Check" type="CompoundRunConfigurationType">
|
||||||
|
<toRun name="Main Lint" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="Main Static Analysis" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="OAS Validate" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="Test" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="Test Lint" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="Test Static Analysis" type="GradleRunConfiguration" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
11
.run/Docker.run.xml
Normal file
11
.run/Docker.run.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Docker" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||||
|
<deployment type="docker-compose.yml">
|
||||||
|
<settings>
|
||||||
|
<option name="envFilePath" value="" />
|
||||||
|
<option name="sourceFilePath" value="compose.yml" />
|
||||||
|
</settings>
|
||||||
|
</deployment>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
24
.run/Main Lint.run.xml
Normal file
24
.run/Main Lint.run.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Main Lint" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="checkstyleMain" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
24
.run/Main Static Analysis.run.xml
Normal file
24
.run/Main Static Analysis.run.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Main Static Analysis" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="spotbugsMain" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
24
.run/OAS Generate.run.xml
Normal file
24
.run/OAS Generate.run.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="OAS Generate" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="generateSwaggerCode" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
24
.run/OAS Validate.run.xml
Normal file
24
.run/OAS Validate.run.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="OAS Validate" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="validateSwagger" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
10
.run/Run.run.xml
Normal file
10
.run/Run.run.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Run" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
|
||||||
|
<module name="Tower-Defence-Server.main" />
|
||||||
|
<option name="SPRING_BOOT_MAIN_CLASS" value="de.towerdefence.server.ServerApplication" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="Postgres" run_configuration_type="docker-deploy" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
24
.run/Test Lint.run.xml
Normal file
24
.run/Test Lint.run.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Test Lint" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="checkstyleTest" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
22
.run/Test Static Analysis.run.xml
Normal file
22
.run/Test Static Analysis.run.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Test Static Analysis" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
12
.run/Test.run.xml
Normal file
12
.run/Test.run.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Test" type="JUnit" factoryName="JUnit">
|
||||||
|
<module name="Project_Management_Tool.test" />
|
||||||
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="" />
|
||||||
|
<option name="METHOD_NAME" value="" />
|
||||||
|
<option name="TEST_OBJECT" value="package" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
1
License.md
Normal file
1
License.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
See License [here](https://git.euph.dev/TowerDefence/.profile/src/branch/main/License.md)
|
2
Readme.md
Normal file
2
Readme.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[![QS Badge](https://git.euph.dev/TowerDefence/Server/actions/workflows/qs.yml/badge.svg?branch=trunk&style=for-the-badge&label=QS)](https://git.euph.dev/TowerDefence/Server/actions?workflow=qs.yml)
|
||||||
|
# Tower Defence - Server
|
5
api/.gen-ignore
Normal file
5
api/.gen-ignore
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
**/*ApiController.java
|
||||||
|
**/*OpenAPISpringBoot.java
|
||||||
|
**/*application.properties
|
||||||
|
**/io/swagger/configuration/HomeController.java
|
||||||
|
**/io/swagger/configuration/SwaggerUiConfiguration.java
|
110
api/api.yml
Normal file
110
api/api.yml
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
title: Tower Defence Server
|
||||||
|
description: An API for talking to the Tower Defence Server
|
||||||
|
version: 0.0.1
|
||||||
|
servers:
|
||||||
|
- url: /api/v1
|
||||||
|
- url: http://localhost:8080/api/v1
|
||||||
|
security:
|
||||||
|
- JWTAuth: []
|
||||||
|
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
JWTAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
schemas:
|
||||||
|
#############################################
|
||||||
|
# UUID #
|
||||||
|
#############################################
|
||||||
|
UUID:
|
||||||
|
description: Unique identifier compatible with [RFC9562](https://datatracker.ietf.org/doc/html/rfc9562)
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
example: f0981749-f550-46cd-b9ce-b6ca7cd0251f
|
||||||
|
#############################################
|
||||||
|
# AdminAuthInfo #
|
||||||
|
#############################################
|
||||||
|
ServerHealth:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
okay:
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- okay
|
||||||
|
#############################################
|
||||||
|
# AdminAuthInfo #
|
||||||
|
#############################################
|
||||||
|
AdminAuthInfo:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- username
|
||||||
|
responses:
|
||||||
|
401Unauthorized:
|
||||||
|
description: "401 - Unauthorized"
|
||||||
|
404NotFound:
|
||||||
|
description: "Not Found"
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
409Conflict:
|
||||||
|
description: "409 - Conflict"
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
500InternalError:
|
||||||
|
description: "500 - Internal Server Error"
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
503ServiceUnavailable:
|
||||||
|
description: "503 - Service Unavailable"
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
paths:
|
||||||
|
/server/health:
|
||||||
|
get:
|
||||||
|
operationId: "ServerGetHealthcheck"
|
||||||
|
tags:
|
||||||
|
- server
|
||||||
|
description: "Endpoint for doing a Healthcheck of the Server"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "A Health-Report of the server"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ServerHealth"
|
||||||
|
500:
|
||||||
|
$ref: "#/components/responses/500InternalError"
|
||||||
|
503:
|
||||||
|
$ref: "#/components/responses/503ServiceUnavailable"
|
||||||
|
/admin/authenticated:
|
||||||
|
get:
|
||||||
|
operationId: "AdminGetAuthenticated"
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
|
description: "Endpoint for Checking if you're authenticated as an admin"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "A Minimal Admin Info for testing if the admin is logged in"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/AdminAuthInfo"
|
||||||
|
401:
|
||||||
|
$ref: "#/components/responses/401Unauthorized"
|
||||||
|
500:
|
||||||
|
$ref: "#/components/responses/500InternalError"
|
||||||
|
503:
|
||||||
|
$ref: "#/components/responses/503ServiceUnavailable"
|
11
api/gen-config.json
Normal file
11
api/gen-config.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"modelPackage": "de.towerdefence.server.oas.models",
|
||||||
|
"apiPackage": "de.towerdefence.server.oas",
|
||||||
|
"invokerPackage": "de.towerdefence.server",
|
||||||
|
"java8": false,
|
||||||
|
"java11": true,
|
||||||
|
"dateLibrary": "java8-localdatetime",
|
||||||
|
"library": "spring-boot3",
|
||||||
|
"defaultInterfaces": false,
|
||||||
|
"serializableModel": true
|
||||||
|
}
|
126
build.gradle.kts
Normal file
126
build.gradle.kts
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import com.github.spotbugs.snom.Confidence
|
||||||
|
import com.github.spotbugs.snom.Effort
|
||||||
|
import com.github.spotbugs.snom.SpotBugsTask
|
||||||
|
import org.hidetake.gradle.swagger.generator.GenerateSwaggerCode
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
java
|
||||||
|
checkstyle
|
||||||
|
id("com.github.spotbugs") version "6.0.23"
|
||||||
|
id("org.springframework.boot") version "3.4.2"
|
||||||
|
id("io.spring.dependency-management") version "1.1.7"
|
||||||
|
id("org.hidetake.swagger.generator") version "2.19.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
checkstyle {
|
||||||
|
toolVersion = "10.21.2"
|
||||||
|
configDirectory = file("src/main/resources/")
|
||||||
|
configFile = file("src/main/resources/checkstyle.xml")
|
||||||
|
}
|
||||||
|
|
||||||
|
spotbugs {
|
||||||
|
toolVersion = "4.8.6"
|
||||||
|
effort.set(Effort.MAX)
|
||||||
|
reportLevel.set(Confidence.LOW)
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "de.towerdefence"
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly {
|
||||||
|
extendsFrom(configurations.annotationProcessor.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Spring
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-websocket")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||||
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
|
|
||||||
|
// Postgres
|
||||||
|
runtimeOnly("org.postgresql:postgresql")
|
||||||
|
|
||||||
|
// Lombok
|
||||||
|
compileOnly("org.projectlombok:lombok")
|
||||||
|
annotationProcessor("org.projectlombok:lombok")
|
||||||
|
|
||||||
|
// Test
|
||||||
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
testImplementation("org.springframework.boot:spring-boot-testcontainers")
|
||||||
|
testImplementation("org.springframework.security:spring-security-test")
|
||||||
|
testImplementation("org.testcontainers:junit-jupiter")
|
||||||
|
testImplementation("org.testcontainers:postgresql")
|
||||||
|
testRuntimeOnly("com.h2database:h2")
|
||||||
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
|
||||||
|
//OAS
|
||||||
|
swaggerCodegen("io.swagger.codegen.v3:swagger-codegen-cli:3.0.61")
|
||||||
|
implementation("io.swagger.core.v3:swagger-annotations:2.2.22")
|
||||||
|
implementation("jakarta.xml.bind:jakarta.xml.bind-api") //Needed for XML/HTML Validation
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<Test> {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
swaggerSources {
|
||||||
|
register("api") {
|
||||||
|
setInputFile(file("${rootDir}/api/api.yml"))
|
||||||
|
code.configFile = file("${rootDir}/api/gen-config.json")
|
||||||
|
val validationTask = validation
|
||||||
|
code(delegateClosureOf<GenerateSwaggerCode> {
|
||||||
|
language = "spring"
|
||||||
|
code.rawOptions =
|
||||||
|
listOf("--ignore-file-override=" + file("${rootDir}/api/.gen-ignore").absolutePath)
|
||||||
|
dependsOn(validationTask)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
withType<Checkstyle> {
|
||||||
|
reports {
|
||||||
|
xml.required.set(true)
|
||||||
|
html.required.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withType<SpotBugsTask> {
|
||||||
|
excludeFilter.set(file("${rootDir}/src/main/resources/spotbugs-exclude.xml"))
|
||||||
|
}
|
||||||
|
processResources {
|
||||||
|
dependsOn(generateSwaggerCode)
|
||||||
|
}
|
||||||
|
withType<Test> {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
named("compileJava").configure {
|
||||||
|
dependsOn(swaggerSources.getByName("api").code)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java.srcDir("${swaggerSources.getByName("api").code.outputDir}/src/main/java")
|
||||||
|
resources.srcDir("${swaggerSources.getByName("api").code.outputDir}/src/main/resources")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
26
compose.yml
Normal file
26
compose.yml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
container_name: tower_defence_postgres
|
||||||
|
image: postgres:16
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=td
|
||||||
|
- POSTGRES_USER=td_user
|
||||||
|
- POSTGRES_PASSWORD=td123
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- "tower_defence_data:/var/lib/postgresql/data"
|
||||||
|
swagger:
|
||||||
|
container_name: tower_defence_swagger
|
||||||
|
image: swaggerapi/swagger-ui:latest
|
||||||
|
environment:
|
||||||
|
SWAGGER_JSON: "/data/api.yml"
|
||||||
|
ports:
|
||||||
|
- "8090:8080"
|
||||||
|
volumes:
|
||||||
|
- "./api/api.yml:/data/api.yml:Z"
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
tower_defence_data:
|
||||||
|
name: tower_defence_data
|
1
gradle.properties
Normal file
1
gradle.properties
Normal file
|
@ -0,0 +1 @@
|
||||||
|
version="0.0.1-SNAPSHOT"
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
6
http/getToken.http
Normal file
6
http/getToken.http
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
grant_type=password&client_id=employee-management-service&username=user&password=test
|
||||||
|
|
||||||
|
> {%client.log(response.body.access_token)%}
|
1
settings.gradle.kts
Normal file
1
settings.gradle.kts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = "Tower-Defence-Server"
|
30
src/main/java/de/towerdefence/server/Config.java
Normal file
30
src/main/java/de/towerdefence/server/Config.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package de.towerdefence.server;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class Config implements WebMvcConfigurer {
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CorsConfigurationSource corsConfigurationSource() {
|
||||||
|
CorsConfiguration configuration = new CorsConfiguration();
|
||||||
|
configuration.setAllowedOrigins(Arrays.asList("*"));
|
||||||
|
configuration.setAllowedMethods(Arrays.asList("*"));
|
||||||
|
configuration.setAllowedHeaders(Arrays.asList("*"));
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
50
src/main/java/de/towerdefence/server/ServerApplication.java
Normal file
50
src/main/java/de/towerdefence/server/ServerApplication.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package de.towerdefence.server;
|
||||||
|
|
||||||
|
import io.swagger.configuration.LocalDateConverter;
|
||||||
|
import io.swagger.configuration.LocalDateTimeConverter;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.boot.ExitCodeGenerator;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.format.FormatterRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@ComponentScan(basePackages = { "de.towerdefence.server", "de.towerdefence.server.oas" , "io.swagger.configuration"})
|
||||||
|
public class ServerApplication implements CommandLineRunner {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... arg0) throws Exception {
|
||||||
|
if (arg0.length > 0 && arg0[0].equals("exitcode")) {
|
||||||
|
throw new ExitException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
new SpringApplication(ServerApplication.class).run(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomDateConfig extends WebMvcConfigurationSupport {
|
||||||
|
@Override
|
||||||
|
public void addFormatters(FormatterRegistry registry) {
|
||||||
|
registry.addConverter(new LocalDateConverter("yyyy-MM-dd"));
|
||||||
|
registry.addConverter(new LocalDateTimeConverter("yyyy-MM-dd'T'HH:mm:ss.SSS"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ExitException extends RuntimeException implements ExitCodeGenerator {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getExitCode() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.towerdefence.server.admin;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.towerdefence.server.auth.UserSession;
|
||||||
|
import de.towerdefence.server.oas.AdminApi;
|
||||||
|
import de.towerdefence.server.oas.models.AdminAuthInfo;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("${openapi.api.base-path:/api/v1}")
|
||||||
|
public class AdminApiController implements AdminApi {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UserSession userSession;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ObjectMapper> getObjectMapper() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<HttpServletRequest> getRequest() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<AdminAuthInfo> adminGetAuthenticated() {
|
||||||
|
AdminAuthInfo authInfo = new AdminAuthInfo();
|
||||||
|
authInfo.setUsername(this.userSession.getUsername());
|
||||||
|
return ResponseEntity.ok(authInfo);
|
||||||
|
}
|
||||||
|
}
|
60
src/main/java/de/towerdefence/server/auth/AuthConfig.java
Normal file
60
src/main/java/de/towerdefence/server/auth/AuthConfig.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package de.towerdefence.server.auth;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableMethodSecurity
|
||||||
|
public class AuthConfig {
|
||||||
|
|
||||||
|
private static final String API_VERSION = "v1";
|
||||||
|
|
||||||
|
private final JWT jwt;
|
||||||
|
|
||||||
|
AuthConfig(JWT jwt) {
|
||||||
|
this.jwt = jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SessionRegistry sessionRegistry() {
|
||||||
|
return new SessionRegistryImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||||
|
return new RegisterSessionAuthenticationStrategy(sessionRegistry());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HttpSessionEventPublisher httpSessionEventPublisher() {
|
||||||
|
return new HttpSessionEventPublisher();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
return http
|
||||||
|
.csrf(Customizer.withDefaults())
|
||||||
|
.authorizeHttpRequests(auth -> auth
|
||||||
|
.requestMatchers("/api/" + API_VERSION + "/admin/**")
|
||||||
|
.authenticated()
|
||||||
|
.anyRequest()
|
||||||
|
.permitAll()
|
||||||
|
)
|
||||||
|
.oauth2ResourceServer(resourceServer -> resourceServer
|
||||||
|
.jwt(jwt -> jwt.jwtAuthenticationConverter(this.jwt.jwtAuthenticationConverter()))
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
71
src/main/java/de/towerdefence/server/auth/JWT.java
Normal file
71
src/main/java/de/towerdefence/server/auth/JWT.java
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package de.towerdefence.server.auth;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||||
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class JWT implements LogoutHandler {
|
||||||
|
private static final String REALM_ACCESS_CLAIM = "realm_access";
|
||||||
|
private static final String ROLES_CLAIM = "roles";
|
||||||
|
private static final String ROLE_PREFIX = "ROLE_";
|
||||||
|
private static final String OIDC_LOGOUT_ROUTE = "/protocol/openid-connect/logout";
|
||||||
|
private static final String OIDC_TOKEN_HINT_QUERY_PARAMETER = "id_token_hin";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RestTemplate template;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||||
|
OidcUser user = (OidcUser) authentication.getPrincipal();
|
||||||
|
String endSessionEndpoint = user.getIssuer() + OIDC_LOGOUT_ROUTE;
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
|
.fromUriString(endSessionEndpoint)
|
||||||
|
.queryParam(OIDC_TOKEN_HINT_QUERY_PARAMETER, user.getIdToken().getTokenValue());
|
||||||
|
|
||||||
|
ResponseEntity<String> logoutResponse = template.getForEntity(builder.toUriString(), String.class);
|
||||||
|
if (logoutResponse.getStatusCode().is2xxSuccessful()) {
|
||||||
|
System.out.println("Logged out successfully");
|
||||||
|
} else {
|
||||||
|
System.out.println("Failed to logout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtAuthenticationConverter jwtAuthenticationConverter() {
|
||||||
|
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||||
|
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
|
||||||
|
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<String, Object> realmAccess = jwt.getClaim(REALM_ACCESS_CLAIM);
|
||||||
|
if (realmAccess == null || !realmAccess.containsKey(ROLES_CLAIM)) {
|
||||||
|
return grantedAuthorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object rolesClaim = realmAccess.get(ROLES_CLAIM);
|
||||||
|
if (!(rolesClaim instanceof List<?>)) {
|
||||||
|
return grantedAuthorities;
|
||||||
|
}
|
||||||
|
for (Object role : (List<?>) rolesClaim) {
|
||||||
|
assert role instanceof String;
|
||||||
|
grantedAuthorities.add(new SimpleGrantedAuthority(ROLE_PREFIX + role));
|
||||||
|
}
|
||||||
|
|
||||||
|
return grantedAuthorities;
|
||||||
|
});
|
||||||
|
return jwtAuthenticationConverter;
|
||||||
|
}
|
||||||
|
}
|
20
src/main/java/de/towerdefence/server/auth/UserSession.java
Normal file
20
src/main/java/de/towerdefence/server/auth/UserSession.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package de.towerdefence.server.auth;
|
||||||
|
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UserSession {
|
||||||
|
public String getToken() {
|
||||||
|
return getPrincipal().getTokenValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return (String) getPrincipal().getClaims().get("preferred_username");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jwt getPrincipal() {
|
||||||
|
return (Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package de.towerdefence.server.server;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.towerdefence.server.oas.ServerApi;
|
||||||
|
import de.towerdefence.server.oas.models.ServerHealth;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("${openapi.api.base-path:/api/v1}")
|
||||||
|
public class ServerApiController implements ServerApi {
|
||||||
|
@Override
|
||||||
|
public Optional<ObjectMapper> getObjectMapper() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<HttpServletRequest> getRequest() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<ServerHealth> serverGetHealthcheck() {
|
||||||
|
ServerHealth health = new ServerHealth();
|
||||||
|
health.setOkay(true);
|
||||||
|
return ResponseEntity.ok(health);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package de.towerdefence.server.server;
|
||||||
|
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
public class ServerWebsocketHandler extends TextWebSocketHandler {
|
||||||
|
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
|
private final Map<WebSocketSession, ScheduledFuture<?>> sessionTaskMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
|
ScheduledFuture<?> scheduledTask = scheduler.scheduleAtFixedRate(
|
||||||
|
() -> sendCurrentTime(session),
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
);
|
||||||
|
sessionTaskMap.put(session, scheduledTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||||
|
try {
|
||||||
|
String responseMessage = "You are Connected to the Tower Defence Server Websocket";
|
||||||
|
session.sendMessage(new TextMessage(responseMessage));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCurrentTime(WebSocketSession session) {
|
||||||
|
ScheduledFuture<?> task = sessionTaskMap.get(session);
|
||||||
|
try {
|
||||||
|
session.sendMessage(new TextMessage(String.valueOf(System.currentTimeMillis())));
|
||||||
|
} catch (IllegalStateException | IOException e) {
|
||||||
|
task.cancel(true);
|
||||||
|
sessionTaskMap.remove(session);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package de.towerdefence.server.server;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSocket
|
||||||
|
public class WebSocketConfig implements WebSocketConfigurer {
|
||||||
|
@Override
|
||||||
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
|
registry.addHandler(new ServerWebsocketHandler(), "/ws/server").setAllowedOrigins("*");
|
||||||
|
}
|
||||||
|
}
|
18
src/main/resources/application.properties
Normal file
18
src/main/resources/application.properties
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# General
|
||||||
|
spring.application.name=Tower Defence Server
|
||||||
|
server.port=8080
|
||||||
|
|
||||||
|
# DB
|
||||||
|
spring.datasource.url=jdbc:postgresql://${TD_DB_HOST:localhost}:${TD_DB_PORT:5432}/${TD_DB_NAME:td}
|
||||||
|
spring.datasource.username=${TD_DB_USER:td_user}
|
||||||
|
spring.datasource.password=${TD_DB_PASS:td123}
|
||||||
|
spring.jpa.hibernate.ddl-auto=create-drop
|
||||||
|
|
||||||
|
# TODO: Replace with our own IAM (After completion of the project)
|
||||||
|
# JWT Auth
|
||||||
|
spring.security.oauth2.client.registration.keycloak.client-id=employee-management-service
|
||||||
|
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
|
||||||
|
spring.security.oauth2.client.registration.keycloak.scope=openid
|
||||||
|
spring.security.oauth2.client.provider.keycloak.issuer-uri=https://keycloak.szut.dev/auth/realms/szut
|
||||||
|
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
|
||||||
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://keycloak.szut.dev/auth/realms/szut
|
7
src/main/resources/checkstyle-ignore.xml
Normal file
7
src/main/resources/checkstyle-ignore.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.2//EN" "https://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||||
|
|
||||||
|
<suppressions>
|
||||||
|
<suppress files="build[\\/]" checks="." />
|
||||||
|
</suppressions>
|
||||||
|
|
21
src/main/resources/checkstyle.xml
Normal file
21
src/main/resources/checkstyle.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||||
|
<module name="Checker">
|
||||||
|
<module name="SuppressionFilter">
|
||||||
|
<property name="file" value="${config_loc}/checkstyle-ignore.xml" />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<property name="severity" value="error" />
|
||||||
|
<property name="tabWidth" value="4" />
|
||||||
|
|
||||||
|
<module name="LineLength">
|
||||||
|
<property name="max" value="120" />
|
||||||
|
</module>
|
||||||
|
<module name="FileTabCharacter">
|
||||||
|
<property name="eachLine" value="true" />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NewlineAtEndOfFile" />
|
||||||
|
|
||||||
|
</module>
|
||||||
|
|
12
src/main/resources/spotbugs-exclude.xml
Normal file
12
src/main/resources/spotbugs-exclude.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<FindBugsFilter
|
||||||
|
xmlns="https://raw.githubusercontent.com/spotbugs/spotbugs/4.8.6/spotbugs/etc/findbugsfilter.xsd">
|
||||||
|
<Match>
|
||||||
|
<Source name="~.*" />
|
||||||
|
<Bug code="EI,EI2" /> <!-- We don't care about these codes -->
|
||||||
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!--Ignore
|
||||||
|
Auto Generated Code -->
|
||||||
|
<Source name="~.*build/.*" />
|
||||||
|
</Match>
|
||||||
|
</FindBugsFilter>
|
35
src/test/java/de/towerdefence/server/IntegrationTest.java
Normal file
35
src/test/java/de/towerdefence/server/IntegrationTest.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package de.towerdefence.server;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@AutoConfigureMockMvc(addFilters = false)
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
public abstract class IntegrationTest {
|
||||||
|
|
||||||
|
protected final static String baseUri = "/api/v1";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected MockMvc mvc;
|
||||||
|
@Autowired
|
||||||
|
protected ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
//repository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void cleanUp() {
|
||||||
|
//repository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
6
src/test/resources/application-test.properties
Normal file
6
src/test/resources/application-test.properties
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
spring.datasource.url=jdbc:h2:mem:test_db
|
||||||
|
spring.datasource.username=test
|
||||||
|
spring.datasource.password=test
|
||||||
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
|
spring.jpa.hibernate.ddl-auto=create-drop
|
||||||
|
|
Loading…
Add table
Reference in a new issue