chore: setup
All checks were successful
Build Application / build (push) Successful in 1m5s
Quality Check / Validate OAS (push) Successful in 39s
Build Application / build-docker (push) Successful in 33s
Build Application / release (push) Successful in 8s
Quality Check / Linting (push) Successful in 1m0s
Quality Check / Testing (push) Successful in 49s
Quality Check / Static Analysis (push) Successful in 1m0s
All checks were successful
Build Application / build (push) Successful in 1m5s
Quality Check / Validate OAS (push) Successful in 39s
Build Application / build-docker (push) Successful in 33s
Build Application / release (push) Successful in 8s
Quality Check / Linting (push) Successful in 1m0s
Quality Check / Testing (push) Successful in 49s
Quality Check / Static Analysis (push) Successful in 1m0s
This commit is contained in:
commit
92f03cd349
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