1
.gitignore
vendored
1
.gitignore
vendored
@ -34,3 +34,4 @@ out/
|
|||||||
.flooignore
|
.flooignore
|
||||||
|
|
||||||
/mysql/db/storage/
|
/mysql/db/storage/
|
||||||
|
/mysql/keycloak/
|
||||||
|
37
README.adoc
37
README.adoc
@ -8,6 +8,43 @@ Private Gruppen kann man nur über einen Beitrittslink beitreten.
|
|||||||
Öffentliche Gruppen kann man ohne diesen beitreten.
|
Öffentliche Gruppen kann man ohne diesen beitreten.
|
||||||
Man kann nach Öffentlichen Gruppen über eine Suchfunktion suchen.
|
Man kann nach Öffentlichen Gruppen über eine Suchfunktion suchen.
|
||||||
|
|
||||||
|
== Stand
|
||||||
|
|
||||||
|
=== Probleme
|
||||||
|
|
||||||
|
* Momentan ist kein Controller getestet
|
||||||
|
* Das Styling ist inkonsistent und skaliert nicht gut auf kleineren screens
|
||||||
|
* Schlecht dokumentiert und Arc42 nicht aktuell
|
||||||
|
* Integrationen nicht implementiert
|
||||||
|
* Gruppenoptionen nicht implementiert
|
||||||
|
* Snapshotting nicht implementiert
|
||||||
|
* Caching funktioniert, aber teilweise nicht konsequent verwendet
|
||||||
|
* Gruppenbeschreibung mit markup nicht implementiert
|
||||||
|
* Invitelink kann nicht regeneriert werden
|
||||||
|
* Seit Implementierung eines Caches ist die API kaputt
|
||||||
|
|
||||||
|
=== Fertig
|
||||||
|
|
||||||
|
* Fast die komplette Logik + Templates + Controller überholt
|
||||||
|
* Verwendung eines Caches anstatt vieler Datenbankanfragen
|
||||||
|
* UI: Templates mit Fragmenten und auslagertem styling vereinfacht, einige Seiten zusammengefasst
|
||||||
|
* Services komplett umstrukturiert, ergeben inhaltlich mehr Sinn und sind kleiner
|
||||||
|
* Konsequenteres Logging, aspektorientiertes Logging
|
||||||
|
* Aktivere Gruppenobjekte mit mehr Validierung
|
||||||
|
* Extratabelle für Invitelinks entfernt, Datenbank vereinfacht
|
||||||
|
* Man kann Änderungen an Gruppen nachvollziehen mit Zeitstempeln und einer Übersichtsseite
|
||||||
|
* Gruppen und Teilnehmerlisten können exportiert werden
|
||||||
|
|
||||||
|
=== Heroku
|
||||||
|
|
||||||
|
Die letzte Version der Anwendung ist unter gruppenfindung.herokuapp.com zu erreichen.
|
||||||
|
Es existieren zwei Defaultuser:
|
||||||
|
|
||||||
|
* Username: orga, Passwort: orga
|
||||||
|
* Username: studentin, Passwort: studentin
|
||||||
|
|
||||||
|
== Ursprüngliche Readme
|
||||||
|
|
||||||
=== Problem
|
=== Problem
|
||||||
|
|
||||||
Die meisten Teilsysteme von MOPS arbeiten mit Gruppierungen von Studenten: Materialien für Lerngruppen/Veranstaltungen, Gruppenportfolios, Gruppenabstimmungen etc.
|
Die meisten Teilsysteme von MOPS arbeiten mit Gruppierungen von Studenten: Materialien für Lerngruppen/Veranstaltungen, Gruppenportfolios, Gruppenabstimmungen etc.
|
||||||
|
51
build.gradle
51
build.gradle
@ -1,11 +1,9 @@
|
|||||||
import com.github.spotbugs.SpotBugsTask
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'org.springframework.boot' version '2.2.5.RELEASE'
|
id 'org.springframework.boot' version '2.2.5.RELEASE'
|
||||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
|
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
|
||||||
id 'java'
|
id 'java'
|
||||||
|
|
||||||
id 'com.github.spotbugs' version '3.0.0'
|
id 'com.github.spotbugs' version '4.0.1'
|
||||||
id 'checkstyle'
|
id 'checkstyle'
|
||||||
id 'pmd'
|
id 'pmd'
|
||||||
}
|
}
|
||||||
@ -14,34 +12,43 @@ group = 'mops'
|
|||||||
version = '0.0.1-SNAPSHOT'
|
version = '0.0.1-SNAPSHOT'
|
||||||
sourceCompatibility = '11'
|
sourceCompatibility = '11'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url = 'https://s3.cs.hhu.de/public/mops/'
|
||||||
|
metadataSources {
|
||||||
|
artifact()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
spotbugs {
|
spotbugs {
|
||||||
|
toolVersion = '4.0.1'
|
||||||
ignoreFailures = false
|
ignoreFailures = false
|
||||||
reportLevel = "high"
|
reportLevel = "high"
|
||||||
effort = "max"
|
effort = "max"
|
||||||
toolVersion = '4.0.0-RC1'
|
showProgress = true
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(SpotBugsTask) {
|
spotbugsMain {
|
||||||
reports {
|
reports {
|
||||||
xml.enabled = false
|
html {
|
||||||
html.enabled = true
|
enabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pmd {
|
pmd {
|
||||||
consoleOutput = true
|
consoleOutput = true
|
||||||
ignoreFailures = true
|
ignoreFailures = true
|
||||||
toolVersion = "6.21.0"
|
toolVersion = "6.22.0"
|
||||||
rulePriority = 5
|
rulePriority = 5
|
||||||
ruleSets = ["category/java/errorprone.xml",
|
ruleSetFiles = files("config/pmd/ruleset.xml")
|
||||||
"category/java/bestpractices.xml",
|
ruleSets = []
|
||||||
"category/java/security.xml",
|
|
||||||
"category/java/performance.xml",
|
|
||||||
"category/java/design.xml"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkstyle {
|
checkstyle {
|
||||||
toolVersion = "8.28"
|
toolVersion = "8.30"
|
||||||
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
|
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
|
||||||
ignoreFailures = true
|
ignoreFailures = true
|
||||||
}
|
}
|
||||||
@ -56,25 +63,18 @@ configurations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url = 'https://s3.cs.hhu.de/public/mops/'
|
|
||||||
metadataSources {
|
|
||||||
artifact()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-aop'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
|
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
|
||||||
implementation 'org.springframework.security.oauth:spring-security-oauth2:2.4.0.RELEASE'
|
implementation 'org.springframework.security.oauth:spring-security-oauth2:2.4.0.RELEASE'
|
||||||
|
|
||||||
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
|
||||||
implementation 'org.keycloak:keycloak-spring-boot-starter:9.0.0'
|
implementation 'org.keycloak:keycloak-spring-boot-starter:9.0.0'
|
||||||
implementation 'org.keycloak.bom:keycloak-adapter-bom:9.0.0'
|
implementation 'org.keycloak.bom:keycloak-adapter-bom:9.0.0'
|
||||||
implementation 'mops:styleguide:2.1.0'
|
implementation 'mops:styleguide:2.1.0'
|
||||||
@ -82,10 +82,11 @@ dependencies {
|
|||||||
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
|
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
|
||||||
implementation 'com.github.javafaker:javafaker:1.0.2'
|
implementation 'com.github.javafaker:javafaker:1.0.2'
|
||||||
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.10.3'
|
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.10.3'
|
||||||
|
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.3'
|
||||||
|
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
annotationProcessor 'org.projectlombok:lombok'
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
|
||||||
runtimeOnly 'com.h2database:h2'
|
runtimeOnly 'com.h2database:h2'
|
||||||
runtimeOnly 'mysql:mysql-connector-java'
|
runtimeOnly 'mysql:mysql-connector-java'
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
<property name="braceAdjustment" value="0"/>
|
<property name="braceAdjustment" value="0"/>
|
||||||
<property name="caseIndent" value="4"/>
|
<property name="caseIndent" value="4"/>
|
||||||
<property name="throwsIndent" value="4"/>
|
<property name="throwsIndent" value="4"/>
|
||||||
<property name="lineWrappingIndentation" value="8"/>
|
<!--<property name="lineWrappingIndentation" value="8"/>-->
|
||||||
<property name="arrayInitIndent" value="4"/>
|
<property name="arrayInitIndent" value="4"/>
|
||||||
</module>
|
</module>
|
||||||
<!-- <module name="VariableDeclarationUsageDistance"/>-->
|
<!-- <module name="VariableDeclarationUsageDistance"/>-->
|
||||||
|
335
config/pmd/ruleset.xml
Normal file
335
config/pmd/ruleset.xml
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
<ruleset name="quickstart"
|
||||||
|
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||||
|
|
||||||
|
<description>PMD Rules</description>
|
||||||
|
|
||||||
|
<!-- BEST PRACTICES -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/AccessorClassGeneration" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/AccessorMethodGeneration" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/ArrayIsStoredDirectly" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/AvoidPrintStackTrace" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/AvoidReassigningParameters" /> -->
|
||||||
|
<rule ref="category/java/bestpractices.xml/AvoidStringBufferField"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/CheckResultSet"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/ConstantsInInterface"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach"/>
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/GuardLogStatement"/>-->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseAfterAnnotation" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseBeforeAnnotation" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseTestAnnotation" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnitAssertionsShouldIncludeMessage" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnitTestContainsTooManyAsserts" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnitTestsShouldIncludeAssert" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/JUnitUseExpected" /> -->
|
||||||
|
<rule ref="category/java/bestpractices.xml/LooseCoupling"/>
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/MethodReturnsInternalArray" /> -->
|
||||||
|
<rule ref="category/java/bestpractices.xml/MissingOverride"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/OneDeclarationPerLine"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/PositionLiteralsFirstInCaseInsensitiveComparisons"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/PositionLiteralsFirstInComparisons"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/PreserveStackTrace"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/ReplaceEnumerationWithIterator" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/ReplaceHashtableWithMap" /> -->
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/ReplaceVectorWithList" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/SystemPrintln" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/UnusedImports"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/ImportFromSamePackage"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue"/>
|
||||||
|
<rule ref="category/java/bestpractices.xml/UseAssertTrueInsteadOfAssertEquals"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
|
||||||
|
<!-- <rule ref="category/java/bestpractices.xml/UseVarargs" /> -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/AtLeastOneConstructor" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/AvoidDollarSigns"/>
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/AvoidFinalLocalVariable" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/AvoidProtectedFieldInFinalClass"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending"/>
|
||||||
|
|
||||||
|
<!-- NAMING CONVENTIONS -->
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/FormalParameterNamingConventions"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/ClassNamingConventions"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/LocalVariableNamingConventions"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/MethodNamingConventions"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/PackageCase"/>
|
||||||
|
|
||||||
|
<!-- UNIMPLEMENTED -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/FieldNamingConventions" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/GenericsNaming"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/LongVariable" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/ShortClassName"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/ShortMethodName"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/ShortVariable"/>
|
||||||
|
|
||||||
|
<!-- OTHER -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/AvoidUsingNativeCode" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/BooleanGetMethodName" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/CallSuperInConstructor" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/CommentDefaultAccessModifier" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/ConfusingTernary" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/ControlStatementBraces"/>
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/DefaultPackage" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/DontImportJavaLang"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/DuplicateImports"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/ExtendsObject"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/ForLoopShouldBeWhileLoop"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/IdenticalCatchBranches"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/MethodArgumentCouldBeFinal" /> -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/MIsLeadingVariableName" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/NoPackage"/>
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/OnlyOneReturn" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/PrematureDeclaration" /> -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/SuspiciousConstantFieldName" /> -->
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/TooManyStaticImports" /> -->
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryAnnotationValueElement"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryModifier"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryReturn"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UselessParentheses"/>
|
||||||
|
<rule ref="category/java/codestyle.xml/UselessQualifiedThis"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/design.xml/AbstractClassWithoutAnyMethod"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/AvoidCatchingGenericException" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/AvoidDeeplyNestedIfStmts" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/AvoidRethrowingException" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/AvoidThrowingNewInstanceOfSameException" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/AvoidThrowingNullPointerException" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/AvoidThrowingRawExceptionTypes" /> -->
|
||||||
|
<rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/CollapsibleIfStatements" /> -->
|
||||||
|
<rule ref="category/java/design.xml/CouplingBetweenObjects"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/DataClass" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/DoNotExtendJavaLangError" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/ExceptionAsFlowControl" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/ExcessiveClassLength" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/ExcessiveImports" /> -->
|
||||||
|
<rule ref="category/java/design.xml/ExcessiveMethodLength"/>
|
||||||
|
<rule ref="category/java/design.xml/ExcessiveParameterList"/>
|
||||||
|
<rule ref="category/java/design.xml/ExcessivePublicCount"/>
|
||||||
|
<rule ref="category/java/design.xml/FinalFieldCouldBeStatic"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/GodClass" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/ImmutableField" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/LawOfDemeter"/>-->
|
||||||
|
<rule ref="category/java/design.xml/LogicInversion"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/design.xml/CyclomaticComplexity"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/NcssCount" /> -->
|
||||||
|
<rule ref="category/java/design.xml/NPathComplexity"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/design.xml/SignatureDeclareThrowsException" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/design.xml/SimplifiedTernary"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/design.xml/SimplifyBooleanAssertion" /> -->
|
||||||
|
<!-- <rule ref="category/java/design.xml/SimplifyBooleanExpressions" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/design.xml/SimplifyBooleanReturns"/>
|
||||||
|
<rule ref="category/java/design.xml/SimplifyConditional"/>
|
||||||
|
<rule ref="category/java/design.xml/SingularField"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/SwitchDensity" /> -->
|
||||||
|
<rule ref="category/java/design.xml/TooManyFields"/>
|
||||||
|
<rule ref="category/java/design.xml/TooManyMethods"/>
|
||||||
|
<rule ref="category/java/design.xml/UselessOverridingMethod"/>
|
||||||
|
<!-- <rule ref="category/java/design.xml/UseObjectForClearerAPI" /> -->
|
||||||
|
<rule ref="category/java/design.xml/UseUtilityClass"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/documentation.xml/CommentContent" /> -->
|
||||||
|
<!-- <rule ref="category/java/documentation.xml/CommentRequired" /> -->
|
||||||
|
<!-- <rule ref="category/java/documentation.xml/CommentSize" /> -->
|
||||||
|
<rule ref="category/java/documentation.xml/UncommentedEmptyConstructor"/>
|
||||||
|
<rule ref="category/java/documentation.xml/UncommentedEmptyMethodBody"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/errorprone.xml/AssignmentInOperand">
|
||||||
|
<properties>
|
||||||
|
<property name="allowWhile" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
<rule ref="category/java/errorprone.xml/AssignmentToNonFinalStatic"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidAccessibilityAlteration"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidAssertAsIdentifier" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidCallingFinalize" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidCatchingNPE" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidCatchingThrowable"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidDuplicateLiterals" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidEnumAsIdentifier" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidFieldNameMatchingMethodName" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidFieldNameMatchingTypeName" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidInstanceofChecksInCatchClause"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidLiteralsInIfCondition" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/AvoidLosingExceptionInformation" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidMultipleUnaryOperators"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/AvoidUsingOctalValues"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/BadComparison"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/BeanMembersShouldSerialize" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/BrokenNullCheck"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/CallSuperFirst" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/CallSuperLast" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/CheckSkipResult"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/ClassCastExceptionWithToArray"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/CloneMethodMustBePublic"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/CloneMethodMustImplementCloneable"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/CloneMethodReturnTypeMustMatchClassName"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/CloneThrowsCloneNotSupportedException"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/CloseResource"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/CompareObjectsWithEquals"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/ConstructorCallsOverridableMethod" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/DataflowAnomalyAnalysis" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/DoNotCallSystemExit" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/errorprone.xml/DoNotExtendJavaLangThrowable"/>
|
||||||
|
<rule ref="category/java/design.xml/DoNotExtendJavaLangError"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/DoNotHardCodeSDCard" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/DoNotThrowExceptionInFinally" /> -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/DontImportSun" /> -->
|
||||||
|
|
||||||
|
<rule ref="category/java/errorprone.xml/DontUseFloatTypeForLoopIndices"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyCatchBlock"/>
|
||||||
|
|
||||||
|
<!-- EMPTY RULES -->
|
||||||
|
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyFinalizer"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyFinallyBlock"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyIfStmt"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyInitializer"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyStatementBlock"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyStatementNotInLoop"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptySwitchStatements"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptySynchronizedBlock"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyTryBlock"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/EmptyWhileStmt"/>
|
||||||
|
|
||||||
|
<rule ref="category/java/errorprone.xml/EqualsNull"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/FinalizeOverloaded" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/FinalizeShouldBeProtected" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/IdempotentOperations"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/InstantiationToGetClass"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/InvalidSlf4jMessageFormat" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/JumbledIncrementer"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/JUnitSpelling" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/JUnitStaticSuite" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/LoggerIsNotStaticFinal" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/MisplacedNullCheck"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/MissingBreakInSwitch"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/MissingSerialVersionUID" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/MoreThanOneLogger" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/NonCaseLabelInSwitchStatement"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/NonStaticInitializer"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/NullAssignment" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/ProperCloneImplementation"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/ProperLogger"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/ReturnEmptyArrayRatherThanNull"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/SimpleDateFormatNeedsLocale" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/SingleMethodSingleton"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/SingletonClassReturningNewInstance"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/StaticEJBFieldShouldBeFinal" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/StringBufferInstantiationWithChar" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/SuspiciousEqualsMethodName"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/SuspiciousHashcodeMethodName"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/SuspiciousOctalEscape"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/TestClassWithoutTestCases" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/UnconditionalIfStatement"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/UnnecessaryBooleanAssertion" /> -->
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/UnnecessaryCaseChange" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/UnnecessaryConversionTemporary"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/UnusedNullCheckInEquals"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/UseCorrectExceptionLogging" /> -->
|
||||||
|
<rule ref="category/java/errorprone.xml/UseEqualsToCompareStrings"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/UselessOperationOnImmutable"/>
|
||||||
|
<rule ref="category/java/errorprone.xml/UseLocaleWithCaseConversions"/>
|
||||||
|
<!-- <rule ref="category/java/errorprone.xml/UseProperClassLoader" /> -->
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel" /> -->
|
||||||
|
<rule ref="category/java/multithreading.xml/AvoidThreadGroup"/>
|
||||||
|
<rule ref="category/java/multithreading.xml/AvoidUsingVolatile"/>
|
||||||
|
<!-- <rule ref="category/java/multithreading.xml/DoNotUseThreads" /> -->
|
||||||
|
<rule ref="category/java/multithreading.xml/DontCallThreadRun"/>
|
||||||
|
<rule ref="category/java/multithreading.xml/DoubleCheckedLocking"/>
|
||||||
|
<rule ref="category/java/multithreading.xml/NonThreadSafeSingleton"/>
|
||||||
|
<!-- <rule ref="category/java/multithreading.xml/UnsynchronizedStaticDateFormatter"/>-->
|
||||||
|
<!-- <rule ref="category/java/multithreading.xml/UseConcurrentHashMap" /> -->
|
||||||
|
<rule ref="category/java/multithreading.xml/UseNotifyAllInsteadOfNotify"/>
|
||||||
|
|
||||||
|
<!-- <rule ref="category/java/performance.xml/AddEmptyString" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/AppendCharacterWithChar" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/AvoidArrayLoops" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/AvoidFileStream" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/AvoidInstantiatingObjectsInLoops" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/AvoidUsingShortType" /> -->
|
||||||
|
<rule ref="category/java/performance.xml/BigIntegerInstantiation"/>
|
||||||
|
<rule ref="category/java/performance.xml/BooleanInstantiation"/>
|
||||||
|
<!-- <rule ref="category/java/performance.xml/ByteInstantiation" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/ConsecutiveLiteralAppends" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/InefficientEmptyStringCheck" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/InefficientStringBuffering" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/InsufficientStringBufferDeclaration" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/IntegerInstantiation" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/LongInstantiation" /> -->
|
||||||
|
<rule ref="category/java/performance.xml/OptimizableToArrayCall"/>
|
||||||
|
<!-- <rule ref="category/java/performance.xml/RedundantFieldInitializer" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/SimplifyStartsWith" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/ShortInstantiation" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/StringInstantiation" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/StringToString" /> -->
|
||||||
|
<rule ref="category/java/performance.xml/TooFewBranchesForASwitchStatement"/>
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UnnecessaryWrapperObjectCreation" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UseArrayListInsteadOfVector" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UseArraysAsList" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UseIndexOfChar" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UselessStringValueOf" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UseStringBufferForStringAppends" /> -->
|
||||||
|
<!-- <rule ref="category/java/performance.xml/UseStringBufferLength" /> -->
|
||||||
|
</ruleset>
|
@ -1,23 +1,50 @@
|
|||||||
version: "3.7"
|
version: "3.7"
|
||||||
services:
|
services:
|
||||||
dbmysql:
|
dbmysql:
|
||||||
image: mysql:5.7
|
image: mysql:8.0
|
||||||
container_name: 'dbmysql'
|
container_name: 'dbmysql'
|
||||||
environment:
|
environment:
|
||||||
MYSQL_DATABASE: 'gruppen2'
|
MYSQL_DATABASE: 'gruppen'
|
||||||
MYSQL_USER: 'root'
|
MYSQL_USER: 'gruppen'
|
||||||
MYSQL_ROOT_PASSWORD: 'geheim'
|
MYSQL_PASSWORD: 'password'
|
||||||
|
MYSQL_ROOT_PASSWORD: 'root'
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- './mysql/db/storage:/var/lib/mysql'
|
- './mysql/db/storage:/var/lib/mysql'
|
||||||
- './mysql/db/entrypoint:/docker-entrypoint-initdb.d/'
|
- './mysql/db/entrypoint:/docker-entrypoint-initdb.d/'
|
||||||
ports:
|
|
||||||
- '3306:3306'
|
keymysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: 'keymysql'
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: 'keycloak'
|
||||||
|
MYSQL_USER: 'keycloak'
|
||||||
|
MYSQL_PASSWORD: 'password'
|
||||||
|
MYSQL_ROOT_PASSWORD: 'root'
|
||||||
|
volumes:
|
||||||
|
- './mysql/keycloak/storage:/var/lib/mysql'
|
||||||
|
keycloak:
|
||||||
|
image: jboss/keycloak
|
||||||
|
container_name: 'keycloak'
|
||||||
|
depends_on:
|
||||||
|
- keymysql
|
||||||
|
environment:
|
||||||
|
DB_VENDOR: 'MYSQL'
|
||||||
|
DB_ADDR: 'keymysql'
|
||||||
|
DB_DATABASE: 'keycloak'
|
||||||
|
DB_USER: 'keycloak'
|
||||||
|
DB_PASSWORD: 'password'
|
||||||
|
KEYCLOAK_USER: 'admin'
|
||||||
|
KEYCLOAK_PASSWORD: 'admin'
|
||||||
|
ports:
|
||||||
|
- '8082:8080'
|
||||||
|
|
||||||
gruppenapp:
|
gruppenapp:
|
||||||
build: .
|
build: .
|
||||||
container_name: 'gruppenapp'
|
container_name: 'gruppenapp'
|
||||||
depends_on:
|
depends_on:
|
||||||
- dbmysql
|
- dbmysql
|
||||||
|
- keycloak
|
||||||
command: ["/app/wait-for-it.sh", "dbmysql:3306", "--", "java", "-Dspring.profiles.active=docker", "-jar", "/app/gruppen2.jar"]
|
command: ["/app/wait-for-it.sh", "dbmysql:3306", "--", "java", "-Dspring.profiles.active=docker", "-jar", "/app/gruppen2.jar"]
|
||||||
ports:
|
ports:
|
||||||
- '8081:8080'
|
- '8081:8080'
|
||||||
|
20
gruppe.yml
20
gruppe.yml
@ -1,20 +0,0 @@
|
|||||||
# Bei "schicht" können Sie 'vormittags', 'nachmittags' oder 'egal' eintragen.
|
|
||||||
|
|
||||||
gruppe: IT-Bois
|
|
||||||
url: https://github.com/hhu-propra2/abschlussprojekt-it-bois
|
|
||||||
names:
|
|
||||||
- killerber4t
|
|
||||||
- tomvahl
|
|
||||||
- AndiBuls
|
|
||||||
- XXNitram
|
|
||||||
- LukasEttel
|
|
||||||
- Mahgs
|
|
||||||
- ChUrl
|
|
||||||
- kasch309
|
|
||||||
notebook: true
|
|
||||||
schicht: nachmittags
|
|
||||||
projektauswahl:
|
|
||||||
- Gruppenbildung
|
|
||||||
- Punkteübersicht
|
|
||||||
- Materialsammlung
|
|
||||||
- Korrektorinnen Bewerbung
|
|
2
lombok.config
Normal file
2
lombok.config
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
lombok.anyConstructor.addConstructorProperties = true
|
||||||
|
lombok.equalsAndHashCode.callSuper = call
|
@ -1,15 +1,10 @@
|
|||||||
CREATE TABLE event
|
CREATE TABLE event
|
||||||
(
|
(
|
||||||
event_id INT PRIMARY KEY AUTO_INCREMENT,
|
event_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
group_id VARCHAR(36) NOT NULL,
|
group_id VARCHAR(36) NOT NULL,
|
||||||
user_id VARCHAR(50),
|
group_version INT NOT NULL,
|
||||||
event_type VARCHAR(36),
|
exec_id VARCHAR(32) NOT NULL,
|
||||||
event_payload JSON
|
target_id VARCHAR(32),
|
||||||
);
|
event_date DATETIME NOT NULL,
|
||||||
|
event_payload JSON NOT NULL
|
||||||
CREATE TABLE invite
|
|
||||||
(
|
|
||||||
invite_id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
group_id VARCHAR(36) NOT NULL,
|
|
||||||
invite_link VARCHAR(36) NOT NULL
|
|
||||||
);
|
);
|
||||||
|
12
mysql/db/schema-heroku.sql
Normal file
12
mysql/db/schema-heroku.sql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
DROP TABLE IF EXISTS event;
|
||||||
|
|
||||||
|
CREATE TABLE event
|
||||||
|
(
|
||||||
|
event_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
group_id VARCHAR(36) NOT NULL,
|
||||||
|
group_version INT NOT NULL,
|
||||||
|
exec_id VARCHAR(32) NOT NULL,
|
||||||
|
target_id VARCHAR(32),
|
||||||
|
event_date DATETIME NOT NULL,
|
||||||
|
event_payload TEXT NOT NULL
|
||||||
|
);
|
@ -2,47 +2,11 @@ package mops.gruppen2;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.service.Contact;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableCaching
|
|
||||||
@EnableSwagger2
|
|
||||||
public class Gruppen2Application {
|
public class Gruppen2Application {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(Gruppen2Application.class, args);
|
SpringApplication.run(Gruppen2Application.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket productAPI() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.select()
|
|
||||||
.paths(PathSelectors.ant("/gruppen2/api/**"))
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("mops.gruppen2"))
|
|
||||||
.build()
|
|
||||||
.apiInfo(apiMetadata());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiInfo apiMetadata() {
|
|
||||||
return new ApiInfo(
|
|
||||||
"Gruppenbildung API",
|
|
||||||
"API zum anfragen/aktualisieren der Gruppendaten.",
|
|
||||||
"0.0.1",
|
|
||||||
"Free to use",
|
|
||||||
new Contact("gruppen2", "https://github.com/hhu-propra2/abschlussprojekt-it-bois", ""),
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
Collections.emptyList()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
62
src/main/java/mops/gruppen2/aspect/LogAspect.java
Normal file
62
src/main/java/mops/gruppen2/aspect/LogAspect.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package mops.gruppen2.aspect;
|
||||||
|
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.aspect.annotation.Trace;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Profile("dev")
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class LogAspect {
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################### POINTCUT ########################################
|
||||||
|
|
||||||
|
|
||||||
|
@Pointcut("within(@mops.gruppen2.aspect.annotation.TraceMethodCalls *)")
|
||||||
|
public void beanAnnotatedWithMonitor() {}
|
||||||
|
|
||||||
|
@Pointcut("execution(public * *(..))")
|
||||||
|
public void publicMethod() {}
|
||||||
|
|
||||||
|
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
|
||||||
|
public void logMethodCalls() {}
|
||||||
|
|
||||||
|
|
||||||
|
// ###################################### ANNOTATIONS ########################################
|
||||||
|
|
||||||
|
|
||||||
|
@Before("@annotation(mops.gruppen2.aspect.annotation.Trace)")
|
||||||
|
public static void logCustom(JoinPoint joinPoint) {
|
||||||
|
log.trace(((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(Trace.class).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before("@annotation(mops.gruppen2.aspect.annotation.TraceMethodCall) || logMethodCalls()")
|
||||||
|
public static void logMethodCall(JoinPoint joinPoint) {
|
||||||
|
log.trace("Methodenaufruf: {} ({})",
|
||||||
|
joinPoint.getSignature().getName(),
|
||||||
|
joinPoint.getSourceLocation().getWithinType().getName().replace("mops.gruppen2.", ""));
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Around("@annotation(mops.gruppen2.aspect.annotation.TraceExecutionTime)")
|
||||||
|
public static Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
joinPoint.proceed();
|
||||||
|
long stop = System.currentTimeMillis();
|
||||||
|
|
||||||
|
log.trace("Ausführungsdauer: {} Millis", stop - start);
|
||||||
|
|
||||||
|
return joinPoint.proceed();
|
||||||
|
}
|
||||||
|
}
|
16
src/main/java/mops/gruppen2/aspect/annotation/Trace.java
Normal file
16
src/main/java/mops/gruppen2/aspect/annotation/Trace.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package mops.gruppen2.aspect.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schreibt eine benutzerdefinierte Nachricht in den Trace-Stream bei Methodenaufruf.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Trace {
|
||||||
|
|
||||||
|
String value();
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package mops.gruppen2.aspect.annotation;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schreibt die Methodenausführdauer in den Trace-Stream.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TraceExecutionTime {
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package mops.gruppen2.aspect.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schreibt eine Nachricht bei Methodenausführung in den Trace-Stream.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TraceMethodCall {
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package mops.gruppen2.aspect.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schreibt eine Nachricht für jede ausgeführte Methode einer Klasse in den Trace-Stream.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TraceMethodCalls {
|
||||||
|
}
|
15
src/main/java/mops/gruppen2/config/FormatterConfig.java
Normal file
15
src/main/java/mops/gruppen2/config/FormatterConfig.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package mops.gruppen2.config;
|
||||||
|
|
||||||
|
import mops.gruppen2.config.converter.StringToLimitConverter;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.format.FormatterRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class FormatterConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFormatters(FormatterRegistry registry) {
|
||||||
|
registry.addConverter(new StringToLimitConverter());
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package mops.gruppen2.config;
|
|||||||
|
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
|
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
|
||||||
|
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -15,15 +16,16 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@KeycloakConfiguration
|
||||||
public class KeycloakConfig {
|
public class KeycloakConfig {
|
||||||
|
|
||||||
@Value("${keycloak.resource}")
|
@Value("${keycloak.resource}")
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
@Value("${keycloak.credentials.secret}")
|
@Value("2e2e5770-c454-4d31-be99-9d8c34c93089")
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
|
|
||||||
@Value("${hhu_keycloak.token-uri}")
|
@Value("https://churl-keycloak.herokuapp.com/auth/realms/Gruppen/protocol/openid-connect/token")
|
||||||
private String tokenUri;
|
private String tokenUri;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -29,7 +29,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
|
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
|
||||||
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||||
|
43
src/main/java/mops/gruppen2/config/SwaggerConfig.java
Normal file
43
src/main/java/mops/gruppen2/config/SwaggerConfig.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package mops.gruppen2.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||||
|
import springfox.documentation.service.ApiInfo;
|
||||||
|
import springfox.documentation.service.Contact;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@Profile("dev")
|
||||||
|
@Configuration
|
||||||
|
@EnableSwagger2
|
||||||
|
public class SwaggerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Docket productAPI() {
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.select()
|
||||||
|
.paths(PathSelectors.ant("/gruppen2/api/**"))
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("mops.gruppen2"))
|
||||||
|
.build()
|
||||||
|
.apiInfo(apiMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiInfo apiMetadata() {
|
||||||
|
return new ApiInfo(
|
||||||
|
"Gruppenbildung API",
|
||||||
|
"API zum anfragen/aktualisieren der Gruppendaten.",
|
||||||
|
"0.0.1",
|
||||||
|
"Free to use",
|
||||||
|
new Contact("gruppen2", "https://github.com/hhu-propra2/abschlussprojekt-it-bois", ""),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
Collections.emptyList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package mops.gruppen2.config.converter;
|
||||||
|
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
|
||||||
|
public class StringToLimitConverter implements Converter<String, Limit> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Limit convert(String value) {
|
||||||
|
return new Limit(Long.parseLong(value));
|
||||||
|
}
|
||||||
|
}
|
@ -1,74 +0,0 @@
|
|||||||
package mops.gruppen2.controller;
|
|
||||||
|
|
||||||
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
import io.swagger.annotations.ApiParam;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.api.GroupRequestWrapper;
|
|
||||||
import mops.gruppen2.domain.event.Event;
|
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
|
||||||
import mops.gruppen2.service.APIFormatterService;
|
|
||||||
import mops.gruppen2.service.EventService;
|
|
||||||
import mops.gruppen2.service.GroupService;
|
|
||||||
import mops.gruppen2.service.UserService;
|
|
||||||
import org.springframework.security.access.annotation.Secured;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Api zum Datenabgleich mit Gruppenfindung.
|
|
||||||
*/
|
|
||||||
//TODO: API-Service?
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/gruppen2/api")
|
|
||||||
public class APIController {
|
|
||||||
|
|
||||||
private final EventService eventService;
|
|
||||||
private final GroupService groupService;
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
public APIController(EventService eventService, GroupService groupService, UserService userService) {
|
|
||||||
this.eventService = eventService;
|
|
||||||
this.groupService = groupService;
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/updateGroups/{lastEventId}")
|
|
||||||
@Secured("ROLE_api_user")
|
|
||||||
@ApiOperation("Gibt alle Gruppen zurück, in denen sich etwas geändert hat")
|
|
||||||
public GroupRequestWrapper updateGroups(@ApiParam("Letzter Status des Anfragestellers") @PathVariable Long lastEventId) throws EventException {
|
|
||||||
List<Event> events = eventService.getNewEvents(lastEventId);
|
|
||||||
|
|
||||||
return APIFormatterService.wrap(eventService.getMaxEventId(), groupService.projectEventList(events));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/getGroupIdsOfUser/{userId}")
|
|
||||||
@Secured("ROLE_api_user")
|
|
||||||
@ApiOperation("Gibt alle Gruppen zurück, in denen sich ein Teilnehmer befindet")
|
|
||||||
public List<String> getGroupIdsOfUser(@ApiParam("Teilnehmer dessen groupIds zurückgegeben werden sollen") @PathVariable String userId) {
|
|
||||||
return userService.getUserGroups(userId).stream()
|
|
||||||
.map(group -> group.getId().toString())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/getGroup/{groupId}")
|
|
||||||
@Secured("ROLE_api_user")
|
|
||||||
@ApiOperation("Gibt die Gruppe mit der als Parameter mitgegebenden groupId zurück")
|
|
||||||
public Group getGroupById(@ApiParam("GruppenId der gefordeten Gruppe") @PathVariable String groupId) throws EventException {
|
|
||||||
List<Event> eventList = eventService.getEventsOfGroup(UUID.fromString(groupId));
|
|
||||||
List<Group> groups = groupService.projectEventList(eventList);
|
|
||||||
|
|
||||||
if (groups.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
package mops.gruppen2.controller;
|
|
||||||
|
|
||||||
import mops.gruppen2.domain.Account;
|
|
||||||
import mops.gruppen2.service.ControllerService;
|
|
||||||
import mops.gruppen2.service.GroupService;
|
|
||||||
import mops.gruppen2.service.KeyCloakService;
|
|
||||||
import mops.gruppen2.service.ValidationService;
|
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.context.annotation.SessionScope;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
@SessionScope
|
|
||||||
@RequestMapping("/gruppen2")
|
|
||||||
public class GroupCreationController {
|
|
||||||
|
|
||||||
private final GroupService groupService;
|
|
||||||
private final ControllerService controllerService;
|
|
||||||
private final ValidationService validationService;
|
|
||||||
|
|
||||||
public GroupCreationController(GroupService groupService, ControllerService controllerService, ValidationService validationService) {
|
|
||||||
this.groupService = groupService;
|
|
||||||
this.controllerService = controllerService;
|
|
||||||
this.validationService = validationService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_actuator"})
|
|
||||||
@GetMapping("/createOrga")
|
|
||||||
public String createGroupAsOrga(KeycloakAuthenticationToken token,
|
|
||||||
Model model) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
model.addAttribute("lectures", groupService.getAllLecturesWithVisibilityPublic());
|
|
||||||
|
|
||||||
return "createOrga";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_actuator"})
|
|
||||||
@PostMapping("/createOrga")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String postCrateGroupAsOrga(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("title") String title,
|
|
||||||
@RequestParam("description") String description,
|
|
||||||
@RequestParam(value = "visibility", required = false) Boolean visibility,
|
|
||||||
@RequestParam(value = "lecture", required = false) Boolean lecture,
|
|
||||||
@RequestParam("userMaximum") Long userMaximum,
|
|
||||||
@RequestParam(value = "maxInfiniteUsers", required = false) Boolean maxInfiniteUsers,
|
|
||||||
@RequestParam(value = "parent", required = false) String parent,
|
|
||||||
@RequestParam(value = "file", required = false) MultipartFile file) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
UUID parentUUID = controllerService.getUUID(parent);
|
|
||||||
|
|
||||||
validationService.checkFields(description, title, userMaximum, maxInfiniteUsers);
|
|
||||||
|
|
||||||
controllerService.createGroupAsOrga(account,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
visibility,
|
|
||||||
lecture,
|
|
||||||
maxInfiniteUsers,
|
|
||||||
userMaximum,
|
|
||||||
parentUUID,
|
|
||||||
file);
|
|
||||||
return "redirect:/gruppen2";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed("ROLE_studentin")
|
|
||||||
@GetMapping("/createStudent")
|
|
||||||
public String createGroupAsStudent(KeycloakAuthenticationToken token,
|
|
||||||
Model model) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
model.addAttribute("lectures", groupService.getAllLecturesWithVisibilityPublic());
|
|
||||||
|
|
||||||
return "createStudent";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed("ROLE_studentin")
|
|
||||||
@PostMapping("/createStudent")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String postCreateGroupAsStudent(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("title") String title,
|
|
||||||
@RequestParam("description") String description,
|
|
||||||
@RequestParam("userMaximum") Long userMaximum,
|
|
||||||
@RequestParam(value = "visibility", required = false) Boolean visibility,
|
|
||||||
@RequestParam(value = "maxInfiniteUsers", required = false) Boolean maxInfiniteUsers,
|
|
||||||
@RequestParam(value = "parent", required = false) String parent) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
UUID parentUUID = controllerService.getUUID(parent);
|
|
||||||
|
|
||||||
validationService.checkFields(description, title, userMaximum, maxInfiniteUsers);
|
|
||||||
|
|
||||||
controllerService.createGroup(account,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
visibility,
|
|
||||||
null,
|
|
||||||
maxInfiniteUsers,
|
|
||||||
userMaximum,
|
|
||||||
parentUUID);
|
|
||||||
|
|
||||||
return "redirect:/gruppen2";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,281 +0,0 @@
|
|||||||
package mops.gruppen2.controller;
|
|
||||||
|
|
||||||
import mops.gruppen2.domain.Account;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.Role;
|
|
||||||
import mops.gruppen2.domain.User;
|
|
||||||
import mops.gruppen2.domain.Visibility;
|
|
||||||
import mops.gruppen2.service.ControllerService;
|
|
||||||
import mops.gruppen2.service.InviteService;
|
|
||||||
import mops.gruppen2.service.KeyCloakService;
|
|
||||||
import mops.gruppen2.service.UserService;
|
|
||||||
import mops.gruppen2.service.ValidationService;
|
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.context.annotation.SessionScope;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
@SessionScope
|
|
||||||
@RequestMapping("/gruppen2")
|
|
||||||
public class GroupDetailsController {
|
|
||||||
|
|
||||||
private final ControllerService controllerService;
|
|
||||||
private final UserService userService;
|
|
||||||
private final ValidationService validationService;
|
|
||||||
private final InviteService inviteService;
|
|
||||||
|
|
||||||
public GroupDetailsController(ControllerService controllerService, UserService userService, ValidationService validationService, InviteService inviteService) {
|
|
||||||
this.controllerService = controllerService;
|
|
||||||
this.userService = userService;
|
|
||||||
this.validationService = validationService;
|
|
||||||
this.inviteService = inviteService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@GetMapping("/details/{id}")
|
|
||||||
public String showGroupDetails(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
HttpServletRequest request,
|
|
||||||
@PathVariable("id") String groupId) {
|
|
||||||
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
UUID parentId = group.getParent();
|
|
||||||
String actualURL = request.getRequestURL().toString();
|
|
||||||
String serverURL = actualURL.substring(0, actualURL.indexOf("gruppen2/"));
|
|
||||||
Group parent = controllerService.getParent(parentId);
|
|
||||||
|
|
||||||
validationService.throwIfGroupNotExisting(group.getTitle());
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
if (!validationService.checkIfUserInGroup(group, user)) {
|
|
||||||
validationService.throwIfNoAccessToPrivate(group, user);
|
|
||||||
model.addAttribute("group", group);
|
|
||||||
model.addAttribute("parentId", parentId);
|
|
||||||
model.addAttribute("parent", parent);
|
|
||||||
return "detailsNoMember";
|
|
||||||
}
|
|
||||||
|
|
||||||
model.addAttribute("parentId", parentId);
|
|
||||||
model.addAttribute("parent", parent);
|
|
||||||
model.addAttribute("group", group);
|
|
||||||
model.addAttribute("roles", group.getRoles());
|
|
||||||
model.addAttribute("user", user);
|
|
||||||
model.addAttribute("admin", Role.ADMIN);
|
|
||||||
model.addAttribute("public", Visibility.PUBLIC);
|
|
||||||
model.addAttribute("private", Visibility.PRIVATE);
|
|
||||||
|
|
||||||
if (validationService.checkIfAdmin(group, user)) {
|
|
||||||
model.addAttribute("link", serverURL + "gruppen2/acceptinvite/" + inviteService.getLinkByGroupId(group.getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return "detailsMember";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@GetMapping("/details/changeMetadata/{id}")
|
|
||||||
public String changeMetadata(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
@PathVariable("id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfNoAdmin(group, user);
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
model.addAttribute("title", group.getTitle());
|
|
||||||
model.addAttribute("description", group.getDescription());
|
|
||||||
model.addAttribute("admin", Role.ADMIN);
|
|
||||||
model.addAttribute("roles", group.getRoles());
|
|
||||||
model.addAttribute("groupId", group.getId());
|
|
||||||
model.addAttribute("user", user);
|
|
||||||
|
|
||||||
return "changeMetadata";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/details/changeMetadata")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String postChangeMetadata(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("title") String title,
|
|
||||||
@RequestParam("description") String description,
|
|
||||||
@RequestParam("groupId") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfNoAdmin(group, user);
|
|
||||||
validationService.checkFields(title, description);
|
|
||||||
|
|
||||||
controllerService.changeMetaData(account, group, title, description);
|
|
||||||
|
|
||||||
return "redirect:/gruppen2/details/" + groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@GetMapping("/details/members/{id}")
|
|
||||||
public String editMembers(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
@PathVariable("id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
User user = new User(account);
|
|
||||||
|
|
||||||
validationService.throwIfNoAdmin(group, user);
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
model.addAttribute("members", group.getMembers());
|
|
||||||
model.addAttribute("group", group);
|
|
||||||
model.addAttribute("admin", Role.ADMIN);
|
|
||||||
|
|
||||||
return "editMembers";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/details/members/changeRole")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String changeRole(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("group_id") String groupId,
|
|
||||||
@RequestParam("user_id") String userId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
User principle = new User(account);
|
|
||||||
User user = new User(userId, "", "", "");
|
|
||||||
|
|
||||||
validationService.throwIfNoAdmin(group, principle);
|
|
||||||
|
|
||||||
//TODO: checkIfAdmin checkt nicht, dass die rolle geändert wurde. oder die rolle wird nicht geändert
|
|
||||||
|
|
||||||
controllerService.changeRole(account, user, group);
|
|
||||||
|
|
||||||
if (!validationService.checkIfAdmin(group, principle)) {
|
|
||||||
return "redirect:/gruppen2/details/" + groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "redirect:/gruppen2/details/members/" + groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/details/members/changeMaximum")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String changeMaxSize(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("maximum") Long maximum,
|
|
||||||
@RequestParam("group_id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfNewMaximumIsValid(maximum, group);
|
|
||||||
|
|
||||||
controllerService.updateMaxUser(account, UUID.fromString(groupId), maximum);
|
|
||||||
|
|
||||||
return "redirect:/gruppen2/details/members/" + groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/details/members/deleteUser")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String deleteUser(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("group_id") String groupId,
|
|
||||||
@RequestParam("user_id") String userId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User principle = new User(account);
|
|
||||||
User user = new User(userId, "", "", "");
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfNoAdmin(group, principle);
|
|
||||||
|
|
||||||
controllerService.deleteUser(account, user, group);
|
|
||||||
|
|
||||||
if (!validationService.checkIfUserInGroup(group, principle)) {
|
|
||||||
return "redirect:/gruppen2";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "redirect:/gruppen2/details/members/" + groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/detailsBeitreten")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String joinGroup(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
@RequestParam("id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfUserAlreadyInGroup(group, user);
|
|
||||||
validationService.throwIfGroupFull(group);
|
|
||||||
|
|
||||||
controllerService.addUser(account, UUID.fromString(groupId));
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
|
|
||||||
return "redirect:/gruppen2";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/leaveGroup")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String leaveGroup(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("group_id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
controllerService.deleteUser(account, user, group);
|
|
||||||
|
|
||||||
return "redirect:/gruppen2";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/deleteGroup")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String deleteGroup(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("group_id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfNoAdmin(group, user);
|
|
||||||
|
|
||||||
controllerService.deleteGroupEvent(user.getId(), UUID.fromString(groupId));
|
|
||||||
|
|
||||||
return "redirect:/gruppen2";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_actuator"})
|
|
||||||
@PostMapping("/details/members/addUsersFromCsv")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String addUsersFromCsv(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("group_id") String groupId,
|
|
||||||
@RequestParam(value = "file", required = false) MultipartFile file) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
controllerService.addUsersFromCsv(account, file, groupId);
|
|
||||||
|
|
||||||
return "redirect:/gruppen2/details/members/" + groupId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
package mops.gruppen2.controller;
|
|
||||||
|
|
||||||
import mops.gruppen2.domain.Account;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.User;
|
|
||||||
import mops.gruppen2.domain.Visibility;
|
|
||||||
import mops.gruppen2.service.ControllerService;
|
|
||||||
import mops.gruppen2.service.InviteService;
|
|
||||||
import mops.gruppen2.service.KeyCloakService;
|
|
||||||
import mops.gruppen2.service.UserService;
|
|
||||||
import mops.gruppen2.service.ValidationService;
|
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.context.annotation.SessionScope;
|
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
@SessionScope
|
|
||||||
@RequestMapping("/gruppen2")
|
|
||||||
public class SearchAndInviteController {
|
|
||||||
|
|
||||||
private final ValidationService validationService;
|
|
||||||
private final InviteService inviteService;
|
|
||||||
private final UserService userService;
|
|
||||||
private final ControllerService controllerService;
|
|
||||||
|
|
||||||
public SearchAndInviteController(ValidationService validationService, InviteService inviteService, UserService userService, ControllerService controllerService) {
|
|
||||||
this.validationService = validationService;
|
|
||||||
this.inviteService = inviteService;
|
|
||||||
this.userService = userService;
|
|
||||||
this.controllerService = controllerService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@GetMapping("/findGroup")
|
|
||||||
public String findGroup(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
@RequestParam(value = "suchbegriff", required = false) String search) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
List<Group> groups = new ArrayList<>();
|
|
||||||
groups = validationService.checkSearch(search, groups, account);
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
model.addAttribute("gruppen", groups);
|
|
||||||
model.addAttribute("inviteService", inviteService);
|
|
||||||
|
|
||||||
return "search";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@GetMapping("/detailsSearch")
|
|
||||||
public String showGroupDetailsNoMember(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
@RequestParam("id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
UUID parentId = group.getParent();
|
|
||||||
Group parent = controllerService.getParent(parentId);
|
|
||||||
User user = new User(account);
|
|
||||||
|
|
||||||
model.addAttribute("account", account);
|
|
||||||
if (validationService.checkIfUserInGroup(group, user)) {
|
|
||||||
return "redirect:/gruppen2/details/" + groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
model.addAttribute("group", group);
|
|
||||||
model.addAttribute("parentId", parentId);
|
|
||||||
model.addAttribute("parent", parent);
|
|
||||||
|
|
||||||
return "detailsNoMember";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@GetMapping("/acceptinvite/{link}")
|
|
||||||
public String acceptInvite(KeycloakAuthenticationToken token,
|
|
||||||
Model model,
|
|
||||||
@PathVariable("link") String link) {
|
|
||||||
|
|
||||||
Group group = userService.getGroupById(inviteService.getGroupIdFromLink(link));
|
|
||||||
|
|
||||||
validationService.throwIfGroupNotExisting(group.getTitle());
|
|
||||||
|
|
||||||
model.addAttribute("account", KeyCloakService.createAccountFromPrincipal(token));
|
|
||||||
model.addAttribute("group", group);
|
|
||||||
|
|
||||||
if (group.getVisibility() == Visibility.PUBLIC) {
|
|
||||||
return "redirect:/gruppen2/details/" + group.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "joinprivate";
|
|
||||||
}
|
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
|
||||||
@PostMapping("/acceptinvite")
|
|
||||||
@CacheEvict(value = "groups", allEntries = true)
|
|
||||||
public String postAcceptInvite(KeycloakAuthenticationToken token,
|
|
||||||
@RequestParam("id") String groupId) {
|
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
|
||||||
User user = new User(account);
|
|
||||||
Group group = userService.getGroupById(UUID.fromString(groupId));
|
|
||||||
|
|
||||||
validationService.throwIfUserAlreadyInGroup(group, user);
|
|
||||||
validationService.throwIfGroupFull(group);
|
|
||||||
|
|
||||||
controllerService.addUser(account, UUID.fromString(groupId));
|
|
||||||
|
|
||||||
return "redirect:/gruppen2/details/" + groupId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,14 @@
|
|||||||
package mops.gruppen2.domain;
|
package mops.gruppen2.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
import org.keycloak.KeycloakPrincipal;
|
||||||
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
public class Account {
|
public class Account {
|
||||||
|
|
||||||
String name; //user_id
|
String name; //user_id
|
||||||
@ -13,4 +17,14 @@ public class Account {
|
|||||||
String givenname;
|
String givenname;
|
||||||
String familyname;
|
String familyname;
|
||||||
Set<String> roles;
|
Set<String> roles;
|
||||||
|
|
||||||
|
public Account(KeycloakAuthenticationToken token) {
|
||||||
|
KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
|
||||||
|
name = principal.getName();
|
||||||
|
email = principal.getKeycloakSecurityContext().getIdToken().getEmail();
|
||||||
|
image = null;
|
||||||
|
givenname = principal.getKeycloakSecurityContext().getIdToken().getGivenName();
|
||||||
|
familyname = principal.getKeycloakSecurityContext().getIdToken().getFamilyName();
|
||||||
|
roles = token.getAccount().getRoles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
package mops.gruppen2.domain;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Repräsentiert den aggregierten Zustand einer Gruppe.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class Group {
|
|
||||||
|
|
||||||
//TODO: List to Hashmap
|
|
||||||
private final List<User> members;
|
|
||||||
private final Map<String, Role> roles;
|
|
||||||
private UUID id;
|
|
||||||
private String title;
|
|
||||||
private String description;
|
|
||||||
private Long userMaximum;
|
|
||||||
private GroupType type;
|
|
||||||
private Visibility visibility;
|
|
||||||
private UUID parent;
|
|
||||||
|
|
||||||
public Group() {
|
|
||||||
members = new ArrayList<>();
|
|
||||||
roles = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package mops.gruppen2.domain;
|
|
||||||
|
|
||||||
public enum GroupType {
|
|
||||||
SIMPLE,
|
|
||||||
LECTURE
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package mops.gruppen2.domain;
|
|
||||||
|
|
||||||
public enum Role {
|
|
||||||
ADMIN,
|
|
||||||
MEMBER
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package mops.gruppen2.domain;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@EqualsAndHashCode(exclude = {"givenname", "familyname", "email"})
|
|
||||||
public class User {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String givenname;
|
|
||||||
private String familyname;
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
public User(Account account) {
|
|
||||||
id = account.getName();
|
|
||||||
givenname = account.getGivenname();
|
|
||||||
familyname = account.getFamilyname();
|
|
||||||
email = account.getEmail();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package mops.gruppen2.domain;
|
|
||||||
|
|
||||||
public enum Visibility {
|
|
||||||
PUBLIC,
|
|
||||||
PRIVATE
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package mops.gruppen2.domain.dto;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.data.annotation.Id;
|
|
||||||
import org.springframework.data.relational.core.mapping.Table;
|
|
||||||
|
|
||||||
@Table("invite")
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class InviteLinkDTO {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
Long invite_id;
|
|
||||||
String group_id;
|
|
||||||
String invite_link;
|
|
||||||
}
|
|
57
src/main/java/mops/gruppen2/domain/event/AddMemberEvent.java
Normal file
57
src/main/java/mops/gruppen2/domain/event/AddMemberEvent.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.GroupFullException;
|
||||||
|
import mops.gruppen2.domain.exception.IdMismatchException;
|
||||||
|
import mops.gruppen2.domain.exception.UserExistsException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fügt einen einzelnen Nutzer einer Gruppe hinzu.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AddMemberEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("user")
|
||||||
|
User user;
|
||||||
|
|
||||||
|
public AddMemberEvent(UUID groupId, String exec, String target, User user) throws IdMismatchException {
|
||||||
|
super(groupId, exec, target);
|
||||||
|
this.user = user;
|
||||||
|
|
||||||
|
if (!target.equals(user.getId())) {
|
||||||
|
throw new IdMismatchException("Der User passt nicht zur angegebenen userid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
|
cache.usersPut(target, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws UserExistsException, GroupFullException {
|
||||||
|
group.addMember(target, user);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Benutzer hinzugefügt: " + target + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.ADDMEMBER.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
package mops.gruppen2.domain.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.Role;
|
|
||||||
import mops.gruppen2.domain.User;
|
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
|
||||||
import mops.gruppen2.domain.exception.GroupFullException;
|
|
||||||
import mops.gruppen2.domain.exception.UserAlreadyExistsException;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt einen einzelnen Nutzer einer Gruppe hinzu.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor // For Jackson
|
|
||||||
public class AddUserEvent extends Event {
|
|
||||||
|
|
||||||
private String givenname;
|
|
||||||
private String familyname;
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
public AddUserEvent(UUID groupId, String userId, String givenname, String familyname, String email) {
|
|
||||||
super(groupId, userId);
|
|
||||||
this.givenname = givenname;
|
|
||||||
this.familyname = familyname;
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyEvent(Group group) throws EventException {
|
|
||||||
User user = new User(userId, givenname, familyname, email);
|
|
||||||
|
|
||||||
if (group.getMembers().contains(user)) {
|
|
||||||
throw new UserAlreadyExistsException(getClass().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group.getMembers().size() >= group.getUserMaximum()) {
|
|
||||||
throw new GroupFullException(getClass().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
group.getMembers().add(user);
|
|
||||||
group.getRoles().put(userId, Role.MEMBER);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +1,56 @@
|
|||||||
package mops.gruppen2.domain.event;
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
import lombok.Getter;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import mops.gruppen2.domain.Group;
|
import lombok.Value;
|
||||||
import mops.gruppen2.domain.GroupType;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.Visibility;
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Getter
|
@Log4j2
|
||||||
@NoArgsConstructor // For Jackson
|
@Value
|
||||||
|
@AllArgsConstructor// Value generiert den allArgsConstrucot nur, wenn keiner explizit angegeben ist
|
||||||
public class CreateGroupEvent extends Event {
|
public class CreateGroupEvent extends Event {
|
||||||
|
|
||||||
private Visibility groupVisibility;
|
@JsonProperty("date")
|
||||||
private UUID groupParent;
|
LocalDateTime date;
|
||||||
private GroupType groupType;
|
|
||||||
private Long groupUserMaximum;
|
|
||||||
|
|
||||||
public CreateGroupEvent(UUID groupId, String userId, UUID parent, GroupType type, Visibility visibility, Long userMaximum) {
|
public CreateGroupEvent(UUID groupId, String exec, LocalDateTime date) {
|
||||||
super(groupId, userId);
|
super(groupId, exec, null);
|
||||||
groupParent = parent;
|
this.date = date;
|
||||||
groupType = type;
|
|
||||||
groupVisibility = visibility;
|
|
||||||
groupUserMaximum = userMaximum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyEvent(Group group) {
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
group.setId(groupId);
|
cache.groupsPut(groupid, group);
|
||||||
group.setParent(groupParent);
|
cache.linksPut(group.getLink(), group);
|
||||||
group.setType(groupType);
|
}
|
||||||
group.setVisibility(groupVisibility);
|
|
||||||
group.setUserMaximum(groupUserMaximum);
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws BadArgumentException {
|
||||||
|
group.setId(groupid);
|
||||||
|
group.setCreator(exec);
|
||||||
|
group.setCreationDate(date);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeue Gruppe: {}", group.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Gruppe erstellt.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.CREATEGROUP.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(" + version + "," + groupid + "," + date + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package mops.gruppen2.domain.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor // For Jackson
|
|
||||||
public class DeleteGroupEvent extends Event {
|
|
||||||
|
|
||||||
public DeleteGroupEvent(UUID groupId, String userId) {
|
|
||||||
super(groupId, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyEvent(Group group) {
|
|
||||||
group.getRoles().clear();
|
|
||||||
group.getMembers().clear();
|
|
||||||
group.setTitle(null);
|
|
||||||
group.setDescription(null);
|
|
||||||
group.setVisibility(null);
|
|
||||||
group.setType(null);
|
|
||||||
group.setParent(null);
|
|
||||||
group.setUserMaximum(0L);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package mops.gruppen2.domain.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.User;
|
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
|
||||||
import mops.gruppen2.domain.exception.UserNotFoundException;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entfernt ein einzelnes Mitglied einer Gruppe.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor // For Jackson
|
|
||||||
public class DeleteUserEvent extends Event {
|
|
||||||
|
|
||||||
public DeleteUserEvent(UUID groupId, String userId) {
|
|
||||||
super(groupId, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyEvent(Group group) throws EventException {
|
|
||||||
for (User user : group.getMembers()) {
|
|
||||||
if (user.getId().equals(this.userId)) {
|
|
||||||
group.getMembers().remove(user);
|
|
||||||
group.getRoles().remove(user.getId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new UserNotFoundException(this.getClass().toString());
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,42 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DestroyGroupEvent extends Event {
|
||||||
|
|
||||||
|
public DestroyGroupEvent(UUID groupId, String exec) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
|
cache.groupsRemove(groupid, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws NoAccessException {
|
||||||
|
group.destroy(exec);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tGelöschte Gruppe: {}", group.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Gruppe gelöscht.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.DESTROYGROUP.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -1,51 +1,119 @@
|
|||||||
package mops.gruppen2.domain.event;
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import mops.gruppen2.domain.Group;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
import mops.gruppen2.domain.exception.GroupIdMismatchException;
|
import mops.gruppen2.domain.exception.IdMismatchException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonSubTypes.Type;
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonTypeInfo.As;
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
||||||
|
|
||||||
@JsonTypeInfo(
|
@Log4j2
|
||||||
use = JsonTypeInfo.Id.NAME,
|
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "class")
|
||||||
property = "type"
|
@JsonSubTypes({@Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
|
||||||
)
|
@Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
|
||||||
@JsonSubTypes({
|
@Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
|
||||||
@JsonSubTypes.Type(value = AddUserEvent.class, name = "AddUserEvent"),
|
@Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
|
||||||
@JsonSubTypes.Type(value = CreateGroupEvent.class, name = "CreateGroupEvent"),
|
@Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
|
||||||
@JsonSubTypes.Type(value = DeleteUserEvent.class, name = "DeleteUserEvent"),
|
@Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
|
||||||
@JsonSubTypes.Type(value = UpdateGroupDescriptionEvent.class, name = "UpdateGroupDescriptionEvent"),
|
@Type(value = SetLimitEvent.class, name = "SETLIMIT"),
|
||||||
@JsonSubTypes.Type(value = UpdateGroupTitleEvent.class, name = "UpdateGroupTitleEvent"),
|
@Type(value = SetParentEvent.class, name = "SETPARENT"),
|
||||||
@JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UpdateRoleEvent"),
|
@Type(value = SetTitleEvent.class, name = "SETTITLE"),
|
||||||
@JsonSubTypes.Type(value = DeleteGroupEvent.class, name = "DeleteGroupEvent"),
|
@Type(value = SetTypeEvent.class, name = "SETTYPE"),
|
||||||
@JsonSubTypes.Type(value = UpdateUserMaxEvent.class, name = "UpdateUserMaxEvent")
|
@Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
|
||||||
})
|
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor // Lombok needs a default constructor in the base class
|
||||||
@AllArgsConstructor
|
|
||||||
public abstract class Event {
|
public abstract class Event {
|
||||||
|
|
||||||
protected UUID groupId;
|
@JsonProperty("groupid")
|
||||||
protected String userId;
|
protected UUID groupid;
|
||||||
|
|
||||||
public void apply(Group group) throws EventException {
|
@JsonProperty("version")
|
||||||
checkGroupIdMatch(group.getId());
|
protected long version; // Group-Version
|
||||||
applyEvent(group);
|
|
||||||
|
@JsonProperty("exec")
|
||||||
|
protected String exec;
|
||||||
|
|
||||||
|
@JsonProperty("target")
|
||||||
|
protected String target;
|
||||||
|
|
||||||
|
@JsonProperty("date")
|
||||||
|
protected LocalDateTime date;
|
||||||
|
|
||||||
|
//TODO: Eigentlich sollte die Gruppe aus dem Cache genommen werden, nicht übergeben
|
||||||
|
public Event(UUID groupid, String exec, String target) {
|
||||||
|
this.groupid = groupid;
|
||||||
|
this.exec = exec;
|
||||||
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkGroupIdMatch(UUID groupId) {
|
public void init(long version) {
|
||||||
if (groupId == null || this.groupId.equals(groupId)) {
|
if (this.version != 0) {
|
||||||
|
throw new BadArgumentException("Event wurde schon initialisiert. (" + type() + ")");
|
||||||
|
}
|
||||||
|
date = LocalDateTime.now();
|
||||||
|
|
||||||
|
log.trace("Event wurde initialisiert. (" + type() + "," + version + ")");
|
||||||
|
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(Group group, GroupCache cache) throws EventException {
|
||||||
|
log.trace("Event wird angewendet:\t{}", this);
|
||||||
|
|
||||||
|
if (version == 0) {
|
||||||
|
throw new BadArgumentException("Event wurde nicht initialisiert.");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkGroupIdMatch(group.getId());
|
||||||
|
group.updateVersion(version);
|
||||||
|
applyEvent(group);
|
||||||
|
updateCache(cache, group); // Update erst nachdem apply keine exception geworfen hat
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(Group group) throws EventException {
|
||||||
|
log.trace("Event wird angewendet:\t{}", this);
|
||||||
|
|
||||||
|
if (version == 0) {
|
||||||
|
throw new BadArgumentException("Event wurde nicht initialisiert.");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkGroupIdMatch(group.getId());
|
||||||
|
group.updateVersion(version);
|
||||||
|
applyEvent(group);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkGroupIdMatch(UUID groupid) throws IdMismatchException {
|
||||||
|
// CreateGroupEvents müssen die Id erst initialisieren
|
||||||
|
if (this instanceof CreateGroupEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new GroupIdMismatchException(getClass().toString());
|
if (!this.groupid.equals(groupid)) {
|
||||||
|
throw new IdMismatchException("Das Event gehört zu einer anderen Gruppe");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void updateCache(GroupCache cache, Group group);
|
||||||
|
|
||||||
protected abstract void applyEvent(Group group) throws EventException;
|
protected abstract void applyEvent(Group group) throws EventException;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public abstract String format();
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public abstract String type();
|
||||||
}
|
}
|
||||||
|
15
src/main/java/mops/gruppen2/domain/event/EventType.java
Normal file
15
src/main/java/mops/gruppen2/domain/event/EventType.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
public enum EventType {
|
||||||
|
ADDMEMBER,
|
||||||
|
CREATEGROUP,
|
||||||
|
DESTROYGROUP,
|
||||||
|
KICKMEMBER,
|
||||||
|
SETDESCRIPTION,
|
||||||
|
SETLINK,
|
||||||
|
SETLIMIT,
|
||||||
|
SETPARENT,
|
||||||
|
SETTITLE,
|
||||||
|
SETTYPE,
|
||||||
|
UPDATEROLE
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.LastAdminException;
|
||||||
|
import mops.gruppen2.domain.exception.UserNotFoundException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt ein einzelnes Mitglied einer Gruppe.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class KickMemberEvent extends Event {
|
||||||
|
|
||||||
|
public KickMemberEvent(UUID groupId, String exec, String target) {
|
||||||
|
super(groupId, exec, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
|
cache.usersRemove(target, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws UserNotFoundException, LastAdminException {
|
||||||
|
group.kickMember(target);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Mitglied entfernt: " + target + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.KICKMEMBER.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ändert nur die Gruppenbeschreibung.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SetDescriptionEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("desc")
|
||||||
|
Description description;
|
||||||
|
|
||||||
|
public SetDescriptionEvent(UUID groupId, String exec, @Valid Description description) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws NoAccessException {
|
||||||
|
group.setDescription(exec, description);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeue Beschreibung: {}", group.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Beschreibung gesetzt: " + description + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.SETDESCRIPTION.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Link;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SetInviteLinkEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("link")
|
||||||
|
Link link;
|
||||||
|
|
||||||
|
public SetInviteLinkEvent(UUID groupId, String exec, @Valid Link link) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
|
cache.linksRemove(group.getLink());
|
||||||
|
cache.linksPut(link.getValue(), group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws NoAccessException {
|
||||||
|
group.setLink(exec, link);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeuer Link: {}", group.getLink());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Einladungslink gesetzt: " + link + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.SETLINK.toString();
|
||||||
|
}
|
||||||
|
}
|
48
src/main/java/mops/gruppen2/domain/event/SetLimitEvent.java
Normal file
48
src/main/java/mops/gruppen2/domain/event/SetLimitEvent.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SetLimitEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("limit")
|
||||||
|
Limit limit;
|
||||||
|
|
||||||
|
public SetLimitEvent(UUID groupId, String exec, @Valid Limit limit) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws BadArgumentException, NoAccessException {
|
||||||
|
group.setLimit(exec, limit);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeues UserLimit: {}", group.getLimit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Benutzerlimit gesetzt: " + limit + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.SETLIMIT.toString();
|
||||||
|
}
|
||||||
|
}
|
48
src/main/java/mops/gruppen2/domain/event/SetParentEvent.java
Normal file
48
src/main/java/mops/gruppen2/domain/event/SetParentEvent.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SetParentEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("parent")
|
||||||
|
Parent parent;
|
||||||
|
|
||||||
|
public SetParentEvent(UUID groupId, String exec, @Valid Parent parent) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws NoAccessException, BadArgumentException {
|
||||||
|
group.setParent(exec, parent);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeues Parent: {}", group.getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Veranstaltungszugehörigkeit gesetzt: " + parent.getValue() + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.SETPARENT.toString();
|
||||||
|
}
|
||||||
|
}
|
51
src/main/java/mops/gruppen2/domain/event/SetTitleEvent.java
Normal file
51
src/main/java/mops/gruppen2/domain/event/SetTitleEvent.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ändert nur den Gruppentitel.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SetTitleEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("title")
|
||||||
|
Title title;
|
||||||
|
|
||||||
|
public SetTitleEvent(UUID groupId, String exec, @Valid Title title) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws NoAccessException {
|
||||||
|
group.setTitle(exec, title);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeuer Titel: {}", group.getTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Titel gesetzt: " + title + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.SETTITLE.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
src/main/java/mops/gruppen2/domain/event/SetTypeEvent.java
Normal file
57
src/main/java/mops/gruppen2/domain/event/SetTypeEvent.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.experimental.NonFinal;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SetTypeEvent extends Event {
|
||||||
|
|
||||||
|
@JsonProperty("type")
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
//TODO: blöder hack, das soll eigentlich anders gehen
|
||||||
|
// Problem ist, dass die Gruppe vor dem Cache verändert wird, also kann der cache den alten Typ
|
||||||
|
// nicht mehr aus der Gruppe holen
|
||||||
|
@NonFinal
|
||||||
|
Type oldType;
|
||||||
|
|
||||||
|
public SetTypeEvent(UUID groupId, String exec, @Valid Type type) {
|
||||||
|
super(groupId, exec, null);
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
|
cache.typesRemove(oldType, group);
|
||||||
|
cache.typesPut(type, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws EventException {
|
||||||
|
oldType = group.getType();
|
||||||
|
group.setType(exec, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Gruppentype gesetzt: " + type + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.SETTYPE.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
package mops.gruppen2.domain.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.exception.BadParameterException;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ändert nur die Gruppenbeschreibung.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor // For Jackson
|
|
||||||
public class UpdateGroupDescriptionEvent extends Event {
|
|
||||||
|
|
||||||
private String newGroupDescription;
|
|
||||||
|
|
||||||
public UpdateGroupDescriptionEvent(UUID groupId, String userId, String newGroupDescription) {
|
|
||||||
super(groupId, userId);
|
|
||||||
this.newGroupDescription = newGroupDescription.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyEvent(Group group) {
|
|
||||||
if (newGroupDescription.isEmpty()) {
|
|
||||||
throw new BadParameterException("Die Beschreibung ist leer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
group.setDescription(newGroupDescription);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package mops.gruppen2.domain.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.exception.BadParameterException;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ändert nur den Gruppentitel.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor // For Jackson
|
|
||||||
public class UpdateGroupTitleEvent extends Event {
|
|
||||||
|
|
||||||
private String newGroupTitle;
|
|
||||||
|
|
||||||
public UpdateGroupTitleEvent(UUID groupId, String userId, String newGroupTitle) {
|
|
||||||
super(groupId, userId);
|
|
||||||
this.newGroupTitle = newGroupTitle.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyEvent(Group group) {
|
|
||||||
if (newGroupTitle.isEmpty()) {
|
|
||||||
throw new BadParameterException("Der Titel ist leer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
group.setTitle(newGroupTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,35 +1,51 @@
|
|||||||
package mops.gruppen2.domain.event;
|
package mops.gruppen2.domain.event;
|
||||||
|
|
||||||
import lombok.Getter;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import mops.gruppen2.domain.Group;
|
import lombok.Value;
|
||||||
import mops.gruppen2.domain.Role;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.LastAdminException;
|
||||||
import mops.gruppen2.domain.exception.UserNotFoundException;
|
import mops.gruppen2.domain.exception.UserNotFoundException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Role;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aktualisiert die Gruppenrolle eines Teilnehmers.
|
* Aktualisiert die Gruppenrolle eines Teilnehmers.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Log4j2
|
||||||
@NoArgsConstructor // For Jackson
|
@Value
|
||||||
|
@AllArgsConstructor
|
||||||
public class UpdateRoleEvent extends Event {
|
public class UpdateRoleEvent extends Event {
|
||||||
|
|
||||||
private Role newRole;
|
@JsonProperty("role")
|
||||||
|
Role role;
|
||||||
|
|
||||||
public UpdateRoleEvent(UUID groupId, String userId, Role newRole) {
|
public UpdateRoleEvent(UUID groupId, String exec, String target, Role role) {
|
||||||
super(groupId, userId);
|
super(groupId, exec, target);
|
||||||
this.newRole = newRole;
|
this.role = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyEvent(Group group) throws UserNotFoundException {
|
protected void updateCache(GroupCache cache, Group group) {}
|
||||||
if (group.getRoles().containsKey(userId)) {
|
|
||||||
group.getRoles().put(userId, newRole);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UserNotFoundException(getClass().toString());
|
@Override
|
||||||
|
protected void applyEvent(Group group) throws UserNotFoundException, LastAdminException {
|
||||||
|
group.memberPutRole(target, role);
|
||||||
|
|
||||||
|
log.trace("\t\t\t\t\tNeue Admin: {}", group.getAdmins());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Mitgliedsrolle gesetzt: " + target + ": " + role + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return EventType.UPDATEROLE.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package mops.gruppen2.domain.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
import mops.gruppen2.domain.exception.BadParameterException;
|
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class UpdateUserMaxEvent extends Event {
|
|
||||||
|
|
||||||
private Long userMaximum;
|
|
||||||
|
|
||||||
public UpdateUserMaxEvent(UUID groupId, String userId, Long userMaximum) {
|
|
||||||
super(groupId, userId);
|
|
||||||
this.userMaximum = userMaximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyEvent(Group group) throws EventException {
|
|
||||||
if (userMaximum <= 0 || userMaximum < group.getMembers().size()) {
|
|
||||||
throw new BadParameterException("Usermaximum zu klein.");
|
|
||||||
}
|
|
||||||
|
|
||||||
group.setUserMaximum(userMaximum);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package mops.gruppen2.domain.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class BadArgumentException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -6757742013238625595L;
|
||||||
|
|
||||||
|
public BadArgumentException(String info) {
|
||||||
|
super(HttpStatus.BAD_REQUEST, "Fehlerhafter Parameter.", info);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
package mops.gruppen2.domain.exception;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
public class BadParameterException extends EventException {
|
|
||||||
|
|
||||||
public BadParameterException(String info) {
|
|
||||||
super(HttpStatus.BAD_REQUEST, "Fehlerhafter Parameter angegeben!", info);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package mops.gruppen2.domain.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class BadPayloadException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -3978242017847155629L;
|
||||||
|
|
||||||
|
public BadPayloadException(String info) {
|
||||||
|
super(HttpStatus.INTERNAL_SERVER_ERROR, "Payload konnte nicht übersetzt werden.", info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,8 +5,10 @@ import org.springframework.web.server.ResponseStatusException;
|
|||||||
|
|
||||||
public class EventException extends ResponseStatusException {
|
public class EventException extends ResponseStatusException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 6784052016028094340L;
|
||||||
|
|
||||||
public EventException(HttpStatus status, String msg, String info) {
|
public EventException(HttpStatus status, String msg, String info) {
|
||||||
super(status, msg + " (" + info + ")");
|
super(status, info.isBlank() ? "" : msg + " (" + info + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class GroupFullException extends EventException {
|
public class GroupFullException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4011141160467668713L;
|
||||||
|
|
||||||
public GroupFullException(String info) {
|
public GroupFullException(String info) {
|
||||||
super(HttpStatus.INTERNAL_SERVER_ERROR, "Die Gruppe hat die maximale Midgliederanzahl bereits erreicht!", info);
|
super(HttpStatus.INTERNAL_SERVER_ERROR, "Gruppe hat maximale Teilnehmeranzahl bereits erreicht.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package mops.gruppen2.domain.exception;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
public class GroupIdMismatchException extends EventException {
|
|
||||||
|
|
||||||
public GroupIdMismatchException(String info) {
|
|
||||||
super(HttpStatus.INTERNAL_SERVER_ERROR, "Falsche Gruppe für Event.", info);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class GroupNotFoundException extends EventException {
|
public class GroupNotFoundException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4738218416842951106L;
|
||||||
|
|
||||||
public GroupNotFoundException(String info) {
|
public GroupNotFoundException(String info) {
|
||||||
super(HttpStatus.NOT_FOUND, "Gruppe wurde nicht gefunden.", info);
|
super(HttpStatus.NOT_FOUND, "Gruppe existiert nicht oder wurde gelöscht.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package mops.gruppen2.domain.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class IdMismatchException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7944077617758922089L;
|
||||||
|
|
||||||
|
public IdMismatchException(String info) {
|
||||||
|
super(HttpStatus.INTERNAL_SERVER_ERROR, "Ids stimmen nicht überein.", info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class InvalidInviteException extends EventException {
|
public class InvalidInviteException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2643001101459427944L;
|
||||||
|
|
||||||
public InvalidInviteException(String info) {
|
public InvalidInviteException(String info) {
|
||||||
super(HttpStatus.NOT_FOUND, "Der Einladungslink ist ungültig.", info);
|
super(HttpStatus.NOT_FOUND, "Einladungslink ist ungültig oder Gruppe wurde gelöscht.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package mops.gruppen2.domain.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class LastAdminException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 9059481382346544288L;
|
||||||
|
|
||||||
|
public LastAdminException(String info) {
|
||||||
|
super(HttpStatus.INTERNAL_SERVER_ERROR, "Gruppe braucht mindestens einen Admin.", info);
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class NoAccessException extends EventException {
|
public class NoAccessException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1696988497122834654L;
|
||||||
|
|
||||||
public NoAccessException(String info) {
|
public NoAccessException(String info) {
|
||||||
super(HttpStatus.FORBIDDEN, "Hier hast du leider keinen Zugriff!", info);
|
super(HttpStatus.FORBIDDEN, "Kein Zugriff.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package mops.gruppen2.domain.exception;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
public class NoAdminAfterActionException extends EventException {
|
|
||||||
|
|
||||||
public NoAdminAfterActionException(String info) {
|
|
||||||
super(HttpStatus.INTERNAL_SERVER_ERROR, "Nach dieser Aktion hätte die Gruppe keinen Admin mehr", info);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class NoInviteExistException extends EventException {
|
public class NoInviteExistException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8092076461455840693L;
|
||||||
|
|
||||||
public NoInviteExistException(String info) {
|
public NoInviteExistException(String info) {
|
||||||
super(HttpStatus.NOT_FOUND, "Für diese Gruppe existiert kein Link.", info);
|
super(HttpStatus.NOT_FOUND, "Für diese Gruppe existiert kein Link.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class PageNotFoundException extends EventException {
|
public class PageNotFoundException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2374509005158710104L;
|
||||||
|
|
||||||
public PageNotFoundException(String info) {
|
public PageNotFoundException(String info) {
|
||||||
super(HttpStatus.NOT_FOUND, "Die Seite wurde nicht gefunden!", info);
|
super(HttpStatus.NOT_FOUND, "Seite wurde nicht gefunden.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package mops.gruppen2.domain.exception;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
public class UserAlreadyExistsException extends EventException {
|
|
||||||
|
|
||||||
public UserAlreadyExistsException(String info) {
|
|
||||||
super(HttpStatus.INTERNAL_SERVER_ERROR, "Der User existiert bereits.", info);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package mops.gruppen2.domain.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class UserExistsException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8150634358760194625L;
|
||||||
|
|
||||||
|
public UserExistsException(String info) {
|
||||||
|
super(HttpStatus.INTERNAL_SERVER_ERROR, "User existiert bereits.", info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class UserNotFoundException extends EventException {
|
public class UserNotFoundException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8347442921199785291L;
|
||||||
|
|
||||||
public UserNotFoundException(String info) {
|
public UserNotFoundException(String info) {
|
||||||
super(HttpStatus.NOT_FOUND, "Der User wurde nicht gefunden.", info);
|
super(HttpStatus.NOT_FOUND, "User existiert nicht.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public class WrongFileException extends EventException {
|
public class WrongFileException extends EventException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -166192514348555116L;
|
||||||
|
|
||||||
public WrongFileException(String info) {
|
public WrongFileException(String info) {
|
||||||
super(HttpStatus.BAD_REQUEST, "Die entsprechende Datei ist keine valide CSV-Datei!", info);
|
super(HttpStatus.BAD_REQUEST, "Datei ist keine valide CSV-Datei.", info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
357
src/main/java/mops/gruppen2/domain/model/group/Group.java
Normal file
357
src/main/java/mops/gruppen2/domain/model/group/Group.java
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
|
import mops.gruppen2.domain.exception.GroupFullException;
|
||||||
|
import mops.gruppen2.domain.exception.IdMismatchException;
|
||||||
|
import mops.gruppen2.domain.exception.LastAdminException;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.exception.UserExistsException;
|
||||||
|
import mops.gruppen2.domain.exception.UserNotFoundException;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Body;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Link;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
|
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.SortHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repräsentiert den aggregierten Zustand einer Gruppe.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Muss beim Start gesetzt werden: groupid, meta
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
|
public class Group {
|
||||||
|
|
||||||
|
// Metainformationen
|
||||||
|
@EqualsAndHashCode.Include
|
||||||
|
private UUID groupid;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private Type type = Type.PRIVATE;
|
||||||
|
|
||||||
|
private Parent parent = Parent.EMPTY();
|
||||||
|
|
||||||
|
private Limit limit = Limit.DEFAULT(); // Add initial user
|
||||||
|
|
||||||
|
private Link link = Link.RANDOM();
|
||||||
|
|
||||||
|
private GroupMeta meta = GroupMeta.EMPTY();
|
||||||
|
|
||||||
|
//TODO: UI set + use for options
|
||||||
|
private final GroupOptions options = GroupOptions.DEFAULT();
|
||||||
|
|
||||||
|
// Inhalt
|
||||||
|
private Title title = Title.EMPTY();
|
||||||
|
|
||||||
|
private Description description = Description.EMPTY();
|
||||||
|
|
||||||
|
//TODO: Asciidoc description
|
||||||
|
private Body body;
|
||||||
|
|
||||||
|
// Integrationen
|
||||||
|
|
||||||
|
// Teilnehmer
|
||||||
|
private final Map<String, Membership> memberships = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
// ####################################### Members ###########################################
|
||||||
|
|
||||||
|
|
||||||
|
public List<User> getMembers() {
|
||||||
|
return SortHelper.sortByMemberRole(new ArrayList<>(memberships.values())).stream()
|
||||||
|
.map(Membership::getUser)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> getRegulars() {
|
||||||
|
return memberships.values().stream()
|
||||||
|
.map(Membership::getUser)
|
||||||
|
.filter(member -> isRegular(member.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> getAdmins() {
|
||||||
|
return memberships.values().stream()
|
||||||
|
.map(Membership::getUser)
|
||||||
|
.filter(member -> isAdmin(member.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role getRole(String userid) {
|
||||||
|
return memberships.get(userid).getRole();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMember(String target, User user) throws UserExistsException, GroupFullException {
|
||||||
|
ValidationHelper.throwIfMember(this, target);
|
||||||
|
ValidationHelper.throwIfGroupFull(this);
|
||||||
|
|
||||||
|
memberships.put(target, new Membership(user, Role.REGULAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kickMember(String target) throws UserNotFoundException, LastAdminException {
|
||||||
|
ValidationHelper.throwIfNoMember(this, target);
|
||||||
|
ValidationHelper.throwIfLastAdmin(this, target);
|
||||||
|
|
||||||
|
memberships.remove(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean memberHasRole(String target, Role role) {
|
||||||
|
ValidationHelper.throwIfNoMember(this, target);
|
||||||
|
|
||||||
|
return memberships.get(target).getRole() == role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void memberPutRole(String target, Role role) throws UserNotFoundException, LastAdminException {
|
||||||
|
ValidationHelper.throwIfNoMember(this, target);
|
||||||
|
if (role == Role.REGULAR) {
|
||||||
|
ValidationHelper.throwIfLastAdmin(this, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
memberships.put(target, memberships.get(target).setRole(role));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMember(String target) {
|
||||||
|
return memberships.containsKey(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAdmin(String target) throws UserNotFoundException {
|
||||||
|
ValidationHelper.throwIfNoMember(this, target);
|
||||||
|
|
||||||
|
return memberships.get(target).getRole() == Role.ADMIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRegular(String target) throws UserNotFoundException {
|
||||||
|
ValidationHelper.throwIfNoMember(this, target);
|
||||||
|
|
||||||
|
return memberships.get(target).getRole() == Role.REGULAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################### Getters #########################################
|
||||||
|
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return groupid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getParent() {
|
||||||
|
return parent.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLimit() {
|
||||||
|
return limit.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLink() {
|
||||||
|
return link.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String creator() {
|
||||||
|
return meta.getCreator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long version() {
|
||||||
|
return meta.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime creationDate() {
|
||||||
|
return meta.getCreationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return memberships.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFull() {
|
||||||
|
return size() >= limit.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
return groupid != null && !CommonHelper.uuidIsEmpty(groupid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic() {
|
||||||
|
return type == Type.PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return type == Type.PRIVATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLecture() {
|
||||||
|
return type == Type.LECTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasParent() {
|
||||||
|
return !parent.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMaterial() {
|
||||||
|
return options.isHasMaterialIntegration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasForums() {
|
||||||
|
return options.isHasForumsIntegration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCalendar() {
|
||||||
|
return options.isHasTermineIntegration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasModules() {
|
||||||
|
return options.isHasModulesIntegration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPortfolios() {
|
||||||
|
return options.isHasPortfolioIntegration();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################## Setters ##########################################
|
||||||
|
|
||||||
|
|
||||||
|
public void setId(UUID groupid) throws BadArgumentException {
|
||||||
|
if (this.groupid != null) {
|
||||||
|
throw new BadArgumentException("GruppenId bereits gesetzt.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.groupid = groupid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String exec, Type type) throws NoAccessException {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String exec, @Valid Title title) throws NoAccessException {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String exec, @Valid Description description) throws NoAccessException {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLimit(String exec, @Valid Limit limit) throws NoAccessException, BadArgumentException {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
|
||||||
|
if (size() > limit.getValue()) {
|
||||||
|
throw new BadArgumentException("Das Userlimit ist zu klein für die Gruppe.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(String exec, @Valid Parent parent) throws NoAccessException, BadArgumentException {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
if (parent.getValue().equals(groupid)) {
|
||||||
|
throw new BadArgumentException("Die Gruppe kann nicht zu sich selbst gehören!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLink(String exec, @Valid Link link) throws NoAccessException {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
if (link.getValue().equals(groupid.toString())) {
|
||||||
|
throw new BadArgumentException("Link kann nicht der GruppenID entsprechen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateVersion(long version) throws IdMismatchException {
|
||||||
|
meta = meta.setVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreator(String target) throws BadArgumentException {
|
||||||
|
meta = meta.setCreator(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreationDate(LocalDateTime date) throws BadArgumentException {
|
||||||
|
meta = meta.setCreationDate(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################### Util ############################################
|
||||||
|
|
||||||
|
|
||||||
|
public void destroy(String userid) throws NoAccessException {
|
||||||
|
if (!isEmpty()) {
|
||||||
|
ValidationHelper.throwIfNoAdmin(this, userid);
|
||||||
|
}
|
||||||
|
|
||||||
|
groupid = null;
|
||||||
|
// Wenn man alles null setzt hat der cache mehr arbeit, weil dieser erst nach der löschung
|
||||||
|
// geupdated wird und sich link und mitgliedschaften selber heraussuchen muss
|
||||||
|
/*type = null;
|
||||||
|
parent = null;
|
||||||
|
limit = null;
|
||||||
|
link = null;
|
||||||
|
meta = null;
|
||||||
|
options = null;
|
||||||
|
title = null;
|
||||||
|
description = null;
|
||||||
|
body = null;
|
||||||
|
memberships = null;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format() {
|
||||||
|
return title + " - " + description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "group("
|
||||||
|
+ (groupid == null ? "groupid: null" : groupid.toString())
|
||||||
|
+ ", "
|
||||||
|
+ (parent == null ? "parent: null" : parent.toString())
|
||||||
|
+ ", "
|
||||||
|
+ (meta == null ? "meta: null" : meta.toString())
|
||||||
|
+ ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Group EMPTY() {
|
||||||
|
return new Group();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getVersion() {
|
||||||
|
return meta.getVersion();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
|
import mops.gruppen2.domain.exception.IdMismatchException;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@ToString
|
||||||
|
class GroupMeta {
|
||||||
|
|
||||||
|
long version;
|
||||||
|
String creator;
|
||||||
|
LocalDateTime creationDate;
|
||||||
|
|
||||||
|
GroupMeta setVersion(long version) throws IdMismatchException {
|
||||||
|
if (this.version >= version) {
|
||||||
|
throw new IdMismatchException("Die Gruppe ist bereits auf einem neueren Stand.");
|
||||||
|
}
|
||||||
|
if (this.version + 1 != version) {
|
||||||
|
throw new IdMismatchException("Es fehlen vorherige Events.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GroupMeta(version, creator, creationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupMeta setCreator(String userid) throws BadArgumentException {
|
||||||
|
if (creator != null) {
|
||||||
|
throw new BadArgumentException("Gruppe hat schon einen Ersteller.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GroupMeta(version, userid, creationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupMeta setCreationDate(LocalDateTime date) throws BadArgumentException {
|
||||||
|
if (creationDate != null) {
|
||||||
|
throw new BadArgumentException("Gruppe hat schon ein Erstellungsdatum.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GroupMeta(version, creator, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GroupMeta EMPTY() {
|
||||||
|
return new GroupMeta(0, null, null);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
//TODO: doooooodododo
|
||||||
|
@Value
|
||||||
|
class GroupOptions {
|
||||||
|
|
||||||
|
// Gruppe
|
||||||
|
boolean showClearname;
|
||||||
|
boolean hasBody;
|
||||||
|
boolean isLeavable;
|
||||||
|
boolean hasLink;
|
||||||
|
|
||||||
|
String customLogo;
|
||||||
|
String customBackground;
|
||||||
|
String customTitle;
|
||||||
|
|
||||||
|
// Integrations
|
||||||
|
boolean hasMaterialIntegration;
|
||||||
|
boolean hasTermineIntegration;
|
||||||
|
boolean hasPortfolioIntegration;
|
||||||
|
boolean hasForumsIntegration;
|
||||||
|
boolean hasModulesIntegration;
|
||||||
|
|
||||||
|
static GroupOptions DEFAULT() {
|
||||||
|
return new GroupOptions(true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
|
public class Membership {
|
||||||
|
|
||||||
|
User user;
|
||||||
|
Role role;
|
||||||
|
|
||||||
|
// LocalDateTime age;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return user.format() + ": " + role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Membership setRole(Role role) {
|
||||||
|
return new Membership(user, role);
|
||||||
|
}
|
||||||
|
}
|
10
src/main/java/mops/gruppen2/domain/model/group/Role.java
Normal file
10
src/main/java/mops/gruppen2/domain/model/group/Role.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
public enum Role {
|
||||||
|
ADMIN,
|
||||||
|
REGULAR;
|
||||||
|
|
||||||
|
public Role toggle() {
|
||||||
|
return this == ADMIN ? REGULAR : ADMIN;
|
||||||
|
}
|
||||||
|
}
|
7
src/main/java/mops/gruppen2/domain/model/group/Type.java
Normal file
7
src/main/java/mops/gruppen2/domain/model/group/Type.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
PUBLIC,
|
||||||
|
PRIVATE,
|
||||||
|
LECTURE
|
||||||
|
}
|
64
src/main/java/mops/gruppen2/domain/model/group/User.java
Normal file
64
src/main/java/mops/gruppen2/domain/model/group/User.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package mops.gruppen2.domain.model.group;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.keycloak.KeycloakPrincipal;
|
||||||
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Value
|
||||||
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@EqualsAndHashCode.Include
|
||||||
|
@Getter(AccessLevel.NONE)
|
||||||
|
@JsonProperty("id")
|
||||||
|
String userid;
|
||||||
|
|
||||||
|
@JsonProperty("givenname")
|
||||||
|
String givenname;
|
||||||
|
|
||||||
|
@JsonProperty("familyname")
|
||||||
|
String familyname;
|
||||||
|
|
||||||
|
@JsonProperty("email")
|
||||||
|
String email;
|
||||||
|
|
||||||
|
public User(KeycloakAuthenticationToken token) {
|
||||||
|
KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
|
||||||
|
userid = principal.getName();
|
||||||
|
givenname = principal.getKeycloakSecurityContext().getIdToken().getGivenName();
|
||||||
|
familyname = principal.getKeycloakSecurityContext().getIdToken().getFamilyName();
|
||||||
|
email = principal.getKeycloakSecurityContext().getIdToken().getEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User identifizieren sich über die Id, mehr wird also manchmal nicht benötigt.
|
||||||
|
*
|
||||||
|
* @param userid Die User Id
|
||||||
|
*/
|
||||||
|
public User(String userid) {
|
||||||
|
this.userid = userid;
|
||||||
|
givenname = "";
|
||||||
|
familyname = "";
|
||||||
|
email = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format() {
|
||||||
|
return givenname + " " + familyname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMember(Group group) {
|
||||||
|
return group.getMembers().contains(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package mops.gruppen2.domain.model.group.wrapper;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
//TODO: do it
|
||||||
|
@Value
|
||||||
|
public class Body {
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package mops.gruppen2.domain.model.group.wrapper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class Description {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Size(min = 4, max = 512)
|
||||||
|
@JsonProperty("value")
|
||||||
|
String value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public static Description EMPTY() {
|
||||||
|
return new Description("EMPTY");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package mops.gruppen2.domain.model.group.wrapper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Max;
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class Limit {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Min(1)
|
||||||
|
@Max(999_999)
|
||||||
|
@JsonProperty("value")
|
||||||
|
long value;
|
||||||
|
|
||||||
|
public static Limit DEFAULT() {
|
||||||
|
return new Limit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.valueOf(value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package mops.gruppen2.domain.model.group.wrapper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class Link {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty("value")
|
||||||
|
UUID value;
|
||||||
|
|
||||||
|
public Link(String value) {
|
||||||
|
this.value = UUID.fromString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Link RANDOM() {
|
||||||
|
return new Link(UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package mops.gruppen2.domain.model.group.wrapper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.Value;
|
||||||
|
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.beans.ConstructorProperties;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@ToString
|
||||||
|
public class Parent {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty("id")
|
||||||
|
UUID value;
|
||||||
|
|
||||||
|
@ConstructorProperties("id")
|
||||||
|
public Parent(@NotBlank @Size(min = 36, max = 36) String parentid) {
|
||||||
|
value = UUID.fromString(parentid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parent EMPTY() {
|
||||||
|
return new Parent("00000000-0000-0000-0000-000000000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return CommonHelper.uuidIsEmpty(value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package mops.gruppen2.domain.model.group.wrapper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class Title {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Size(min = 4, max = 128)
|
||||||
|
@JsonProperty("value")
|
||||||
|
String value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public static Title EMPTY() {
|
||||||
|
return new Title("EMPTY");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
package mops.gruppen2.domain.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.event.Event;
|
||||||
|
import mops.gruppen2.domain.exception.BadPayloadException;
|
||||||
|
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.FileHelper;
|
||||||
|
import mops.gruppen2.persistance.EventRepository;
|
||||||
|
import mops.gruppen2.persistance.dto.EventDTO;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class EventStoreService {
|
||||||
|
|
||||||
|
private final EventRepository eventStore;
|
||||||
|
|
||||||
|
|
||||||
|
//########################################### SAVE ###########################################
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt ein DTO aus einem Event und speicher es.
|
||||||
|
*
|
||||||
|
* @param event Event, welches gespeichert wird
|
||||||
|
*/
|
||||||
|
public void saveEvent(Event event) {
|
||||||
|
eventStore.save(getDTOFromEvent(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAll(Event... events) {
|
||||||
|
for (Event event : events) {
|
||||||
|
eventStore.save(getDTOFromEvent(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//########################################### DTOs ###########################################
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt aus einem Event Objekt ein EventDTO Objekt.
|
||||||
|
*
|
||||||
|
* @param event Event, welches in DTO übersetzt wird
|
||||||
|
*
|
||||||
|
* @return EventDTO (Neues DTO)
|
||||||
|
*/
|
||||||
|
private static EventDTO getDTOFromEvent(Event event) {
|
||||||
|
try {
|
||||||
|
String payload = FileHelper.serializeEventJson(event);
|
||||||
|
return new EventDTO(null,
|
||||||
|
event.getGroupid().toString(),
|
||||||
|
event.getVersion(),
|
||||||
|
event.getExec(),
|
||||||
|
event.getTarget(),
|
||||||
|
Timestamp.valueOf(event.getDate()),
|
||||||
|
payload);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("Event ({}) konnte nicht serialisiert werden!", event, e);
|
||||||
|
throw new BadPayloadException(EventStoreService.class.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt aus einer Liste von eventDTOs eine Liste von Events.
|
||||||
|
*
|
||||||
|
* @param eventDTOS Liste von DTOs
|
||||||
|
*
|
||||||
|
* @return Liste von Events
|
||||||
|
*/
|
||||||
|
private static List<Event> getEventsFromDTOs(List<EventDTO> eventDTOS) {
|
||||||
|
return eventDTOS.stream()
|
||||||
|
.map(EventStoreService::getEventFromDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Event getEventFromDTO(EventDTO dto) {
|
||||||
|
try {
|
||||||
|
return FileHelper.deserializeEventJson(dto.getEvent_payload());
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("Payload {} konnte nicht deserialisiert werden!", dto.getEvent_payload(), e);
|
||||||
|
throw new BadPayloadException(EventStoreService.class.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #################################### SIMPLE QUERIES #######################################
|
||||||
|
|
||||||
|
|
||||||
|
public List<Event> findAllEvents() {
|
||||||
|
return getEventsFromDTOs(eventStore.findAllEvents());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Event> findGroupEvents(UUID groupId) {
|
||||||
|
return getEventsFromDTOs(eventStore.findGroupEvents(groupId.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Event> findGroupEvents(List<UUID> ids) {
|
||||||
|
return ids.stream()
|
||||||
|
.map(id -> eventStore.findGroupEvents(id.toString()))
|
||||||
|
.map(EventStoreService::getEventsFromDTOs)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> findGroupPayloads(UUID groupId) {
|
||||||
|
return eventStore.findGroupPayloads(groupId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EventDTO> findGroupDTOs(UUID groupid) {
|
||||||
|
return eventStore.findGroupEvents(groupid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UUID> findChangedGroups(long eventid) {
|
||||||
|
return CommonHelper.stringsToUUID(eventStore.findChangedGroupIds(eventid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long findMaxEventId() {
|
||||||
|
return eventStore.findMaxEventId();
|
||||||
|
}
|
||||||
|
}
|
280
src/main/java/mops/gruppen2/domain/service/GroupService.java
Normal file
280
src/main/java/mops/gruppen2/domain/service/GroupService.java
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
package mops.gruppen2.domain.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.event.AddMemberEvent;
|
||||||
|
import mops.gruppen2.domain.event.CreateGroupEvent;
|
||||||
|
import mops.gruppen2.domain.event.DestroyGroupEvent;
|
||||||
|
import mops.gruppen2.domain.event.Event;
|
||||||
|
import mops.gruppen2.domain.event.KickMemberEvent;
|
||||||
|
import mops.gruppen2.domain.event.SetDescriptionEvent;
|
||||||
|
import mops.gruppen2.domain.event.SetInviteLinkEvent;
|
||||||
|
import mops.gruppen2.domain.event.SetLimitEvent;
|
||||||
|
import mops.gruppen2.domain.event.SetParentEvent;
|
||||||
|
import mops.gruppen2.domain.event.SetTitleEvent;
|
||||||
|
import mops.gruppen2.domain.event.SetTypeEvent;
|
||||||
|
import mops.gruppen2.domain.event.UpdateRoleEvent;
|
||||||
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Role;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Link;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behandelt Aufgaben, welche sich auf eine Gruppe beziehen.
|
||||||
|
* Es werden übergebene Gruppen bearbeitet und dementsprechend Events erzeugt und gespeichert.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class GroupService {
|
||||||
|
|
||||||
|
private final GroupCache groupCache;
|
||||||
|
private final EventStoreService eventStoreService;
|
||||||
|
|
||||||
|
// ################################# GRUPPE ERSTELLEN ########################################
|
||||||
|
|
||||||
|
|
||||||
|
public Group createGroup(String exec) {
|
||||||
|
return createGroup(UUID.randomUUID(), exec, LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initGroupMembers(Group group,
|
||||||
|
String exec,
|
||||||
|
String target,
|
||||||
|
User user,
|
||||||
|
Limit limit) {
|
||||||
|
|
||||||
|
addMember(group, exec, target, user);
|
||||||
|
updateRole(group, exec, target, Role.ADMIN);
|
||||||
|
setLimit(group, exec, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initGroupMeta(Group group,
|
||||||
|
String exec,
|
||||||
|
Type type,
|
||||||
|
Parent parent) {
|
||||||
|
|
||||||
|
setType(group, exec, type);
|
||||||
|
setParent(group, exec, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initGroupText(Group group,
|
||||||
|
String exec,
|
||||||
|
Title title,
|
||||||
|
Description description) {
|
||||||
|
|
||||||
|
setTitle(group, exec, title);
|
||||||
|
setDescription(group, exec, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ################################### GRUPPEN ÄNDERN ########################################
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fügt eine Liste von Usern zu einer Gruppe hinzu.
|
||||||
|
* Duplikate werden übersprungen, die erzeugten Events werden gespeichert.
|
||||||
|
* Dabei wird das Teilnehmermaximum eventuell angehoben.
|
||||||
|
* Prüft, ob der User Admin ist.
|
||||||
|
*
|
||||||
|
* @param newUsers Userliste
|
||||||
|
* @param group Gruppe
|
||||||
|
* @param exec Ausführender User
|
||||||
|
*/
|
||||||
|
public void addUsersToGroup(Group group, String exec, List<User> newUsers) {
|
||||||
|
List<User> users = newUsers.stream().distinct().collect(Collectors.toUnmodifiableList());
|
||||||
|
|
||||||
|
setLimit(group, exec, getAdjustedUserLimit(users, group));
|
||||||
|
|
||||||
|
users.forEach(newUser -> addUserSilent(group, exec, newUser.getId(), newUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt ein passendes Teilnehmermaximum.
|
||||||
|
* Reicht das alte Maximum, wird dieses zurückgegeben.
|
||||||
|
* Ansonsten wird ein erhöhtes Maximum zurückgegeben.
|
||||||
|
*
|
||||||
|
* @param newUsers Neue Teilnehmer
|
||||||
|
* @param group Bestehende Gruppe, welche verändert wird
|
||||||
|
*
|
||||||
|
* @return Das neue Teilnehmermaximum
|
||||||
|
*/
|
||||||
|
private static Limit getAdjustedUserLimit(List<User> newUsers, Group group) {
|
||||||
|
return new Limit(Math.max((long) group.size() + newUsers.size(), group.getLimit()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wechselt die Rolle eines Teilnehmers von Admin zu Member oder andersherum.
|
||||||
|
* Überprüft, ob der User Mitglied ist und ob er der letzte Admin ist.
|
||||||
|
*
|
||||||
|
* @param target Teilnehmer, welcher geändert wird
|
||||||
|
* @param group Gruppe, in welcher sih der Teilnehmer befindet
|
||||||
|
*
|
||||||
|
* @throws EventException Falls der User nicht gefunden wird
|
||||||
|
*/
|
||||||
|
public void toggleMemberRole(Group group, String exec, String target) {
|
||||||
|
ValidationHelper.throwIfNoMember(group, target);
|
||||||
|
|
||||||
|
updateRole(group, exec, target, group.getRole(target).toggle());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ################################# SINGLE EVENTS ###########################################
|
||||||
|
// Spezifische Events werden erzeugt, validiert, auf die Gruppe angewandt und gespeichert
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt eine Gruppe, speichert diese und gibt diese zurück.
|
||||||
|
*/
|
||||||
|
private Group createGroup(UUID groupid, String exec, LocalDateTime date) {
|
||||||
|
Event event = new CreateGroupEvent(groupid,
|
||||||
|
exec,
|
||||||
|
date);
|
||||||
|
Group group = Group.EMPTY();
|
||||||
|
applyAndSave(group, event);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dasselbe wie addUser(), aber exceptions werden abgefangen und nicht geworfen.
|
||||||
|
*/
|
||||||
|
private void addUserSilent(Group group, String exec, String target, User user) {
|
||||||
|
try {
|
||||||
|
addMember(group, exec, target, user);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("Doppelter User {} wurde nicht zu Gruppe {} hinzugefügt!", user, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein AddUserEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer schon Mitglied ist und ob Gruppe voll ist.
|
||||||
|
*/
|
||||||
|
public void addMember(Group group, String exec, String target, User user) {
|
||||||
|
applyAndSave(group, new AddMemberEvent(group.getId(), exec, target, user));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein DeleteUserEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer Mitglied ist und ob er der letzte Admin ist.
|
||||||
|
*/
|
||||||
|
public void kickMember(Group group, String exec, String target) {
|
||||||
|
applyAndSave(group, new KickMemberEvent(group.getId(), exec, target));
|
||||||
|
|
||||||
|
if (group.isEmpty()) {
|
||||||
|
deleteGroup(group, exec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein DeleteGroupEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer Admin ist.
|
||||||
|
*/
|
||||||
|
public void deleteGroup(Group group, String exec) {
|
||||||
|
if (!group.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new DestroyGroupEvent(group.getId(), exec));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein UpdateTitleEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer Admin ist und ob der Titel valide ist.
|
||||||
|
* Bei keiner Änderung wird nichts erzeugt.
|
||||||
|
*/
|
||||||
|
public void setTitle(Group group, String exec, @Valid Title title) {
|
||||||
|
if (group.getTitle().equals(title.getValue())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new SetTitleEvent(group.getId(), exec, title));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein UpdateDescriptiopnEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer Admin ist und ob die Beschreibung valide ist.
|
||||||
|
* Bei keiner Änderung wird nichts erzeugt.
|
||||||
|
*/
|
||||||
|
public void setDescription(Group group, String exec, @Valid Description description) {
|
||||||
|
if (group.getDescription().equals(description.getValue())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new SetDescriptionEvent(group.getId(), exec, description));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein UpdateRoleEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer Mitglied ist.
|
||||||
|
* Bei keiner Änderung wird nichts erzeugt.
|
||||||
|
*/
|
||||||
|
private void updateRole(Group group, String exec, String target, Role role) {
|
||||||
|
if (group.memberHasRole(target, role)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new UpdateRoleEvent(group.getId(), exec, target, role));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt, speichert ein UpdateUserLimitEvent und wendet es auf eine Gruppe an.
|
||||||
|
* Prüft, ob der Nutzer Admin ist und ob das Limit valide ist.
|
||||||
|
* Bei keiner Änderung wird nichts erzeugt.
|
||||||
|
*/
|
||||||
|
public void setLimit(Group group, String exec, @Valid Limit userLimit) {
|
||||||
|
if (userLimit.getValue() == group.getLimit()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new SetLimitEvent(group.getId(), exec, userLimit));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(Group group, String exec, Parent parent) {
|
||||||
|
if (parent.getValue() == group.getParent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new SetParentEvent(group.getId(), exec, parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: UI Link regenerieren button
|
||||||
|
public void setLink(Group group, String exec, @Valid Link link) {
|
||||||
|
if (group.getLink().equals(link.getValue())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new SetInviteLinkEvent(group.getId(), exec, link));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setType(Group group, String exec, Type type) {
|
||||||
|
if (group.getType() == type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyAndSave(group, new SetTypeEvent(group.getId(), exec, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyAndSave(Group group, Event event) throws EventException {
|
||||||
|
event.init(group.version() + 1);
|
||||||
|
event.apply(group, groupCache);
|
||||||
|
|
||||||
|
eventStoreService.saveEvent(event);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package mops.gruppen2.domain.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Log4j2
|
||||||
|
public class SearchService {
|
||||||
|
|
||||||
|
private final GroupCache groupCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filtert alle öffentliche Gruppen nach dem Suchbegriff und gibt diese als sortierte Liste zurück.
|
||||||
|
* Groß- und Kleinschreibung wird nicht beachtet.
|
||||||
|
* Der Suchbegriff wird im Gruppentitel und in der Beschreibung gesucht.
|
||||||
|
*
|
||||||
|
* @param search Der Suchstring
|
||||||
|
*
|
||||||
|
* @return Liste von projizierten Gruppen
|
||||||
|
*
|
||||||
|
* @throws EventException Projektionsfehler
|
||||||
|
*/
|
||||||
|
public List<Group> searchString(String search, String principal) {
|
||||||
|
List<Group> groups = new ArrayList<>();
|
||||||
|
groups.addAll(groupCache.publics());
|
||||||
|
groups.addAll(groupCache.lectures());
|
||||||
|
groups = removeUserGroups(groups, principal);
|
||||||
|
|
||||||
|
if (search.isEmpty()) {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Es wurde gesucht nach: {}", search);
|
||||||
|
return groups.stream()
|
||||||
|
.filter(group -> group.format().toLowerCase().contains(search.toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> searchType(Type type, String principal) {
|
||||||
|
log.debug("Es wurde gesucht nach: {}", type);
|
||||||
|
|
||||||
|
if (type == Type.LECTURE) {
|
||||||
|
return removeUserGroups(groupCache.lectures(), principal);
|
||||||
|
}
|
||||||
|
if (type == Type.PUBLIC) {
|
||||||
|
return removeUserGroups(groupCache.publics(), principal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Group> removeUserGroups(List<Group> groups, String principal) {
|
||||||
|
return groups.stream()
|
||||||
|
.filter(group -> !group.isMember(principal))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package mops.gruppen2.domain.service.helper;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
|
||||||
|
import mops.gruppen2.infrastructure.api.GroupWrapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class APIHelper {
|
||||||
|
|
||||||
|
public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
||||||
|
return new GroupRequestWrapper(status, wrap(groupList));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<GroupWrapper> wrap(List<Group> groups) {
|
||||||
|
return groups.stream()
|
||||||
|
.map(GroupWrapper::new)
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package mops.gruppen2.domain.service.helper;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class CommonHelper {
|
||||||
|
|
||||||
|
public static boolean uuidIsEmpty(UUID uuid) {
|
||||||
|
return "00000000-0000-0000-0000-000000000000".equals(uuid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<UUID> stringsToUUID(List<String> changedGroupIds) {
|
||||||
|
return changedGroupIds.stream()
|
||||||
|
.map(UUID::fromString)
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,148 @@
|
|||||||
|
package mops.gruppen2.domain.service.helper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectReader;
|
||||||
|
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.event.Event;
|
||||||
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
|
import mops.gruppen2.domain.exception.GroupNotFoundException;
|
||||||
|
import mops.gruppen2.domain.exception.WrongFileException;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
import mops.gruppen2.persistance.dto.EventDTO;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class FileHelper {
|
||||||
|
|
||||||
|
// ######################################## CSV #############################################
|
||||||
|
|
||||||
|
|
||||||
|
public static List<User> readCsvFile(MultipartFile file) throws EventException {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<User> userList = readCsv(file.getInputStream());
|
||||||
|
return userList.stream()
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList()); //filter duplicates from list
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("File konnte nicht gelesen werden!", e);
|
||||||
|
throw new WrongFileException(file.getOriginalFilename());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<User> readCsv(InputStream stream) throws IOException {
|
||||||
|
CsvMapper mapper = new CsvMapper();
|
||||||
|
|
||||||
|
CsvSchema schema = mapper.schemaFor(User.class).withHeader().withColumnReordering(true);
|
||||||
|
ObjectReader reader = mapper.readerFor(User.class).with(schema);
|
||||||
|
|
||||||
|
return reader.<User>readValues(stream).readAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String writeCsvUserList(List<User> members) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("id,givenname,familyname,email\n");
|
||||||
|
|
||||||
|
members.forEach(user -> builder.append(user.getId())
|
||||||
|
.append(",")
|
||||||
|
.append(user.getGivenname())
|
||||||
|
.append(",")
|
||||||
|
.append(user.getFamilyname())
|
||||||
|
.append(",")
|
||||||
|
.append(user.getEmail())
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ########################################## JSON ###########################################
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Übersetzt eine Java-Event-Repräsentation zu einem JSON-Event-Payload.
|
||||||
|
*
|
||||||
|
* @param event Java-Event-Repräsentation
|
||||||
|
*
|
||||||
|
* @return JSON-Event-Payload als String
|
||||||
|
*
|
||||||
|
* @throws JsonProcessingException Bei JSON Fehler
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String serializeEventJson(Event event) throws JsonProcessingException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||||
|
String payload = mapper.writeValueAsString(event);
|
||||||
|
log.trace(payload);
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Übersetzt eine JSON-Event-Payload zu einer Java-Event-Repräsentation.
|
||||||
|
*
|
||||||
|
* @param json JSON-Event-Payload als String
|
||||||
|
*
|
||||||
|
* @return Java-Event-Repräsentation
|
||||||
|
*
|
||||||
|
* @throws JsonProcessingException Bei JSON Fehler
|
||||||
|
*/
|
||||||
|
public static Event deserializeEventJson(String json) throws JsonProcessingException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||||
|
Event event = mapper.readValue(json, Event.class);
|
||||||
|
log.trace(event);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ############################################### TXT #######################################
|
||||||
|
|
||||||
|
|
||||||
|
public static String payloadsToPlain(List<String> payloads) {
|
||||||
|
return payloads.stream()
|
||||||
|
.map(payload -> payload + "\n")
|
||||||
|
.reduce((String payloadA, String payloadB) -> payloadA + payloadB)
|
||||||
|
.orElseThrow(() -> new GroupNotFoundException("Keine Payloads gefunden."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String eventDTOsToSql(List<EventDTO> dtos) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
builder.append("INSERT INTO event(group_id, group_version, exec_id, target_id, event_date, event_payload)\nVALUES\n");
|
||||||
|
|
||||||
|
dtos.forEach(dto -> builder.append("('")
|
||||||
|
.append(dto.getGroup_id())
|
||||||
|
.append("','")
|
||||||
|
.append(dto.getGroup_version())
|
||||||
|
.append("','")
|
||||||
|
.append(dto.getExec_id())
|
||||||
|
.append("','")
|
||||||
|
.append(dto.getTarget_id())
|
||||||
|
.append("','")
|
||||||
|
.append(dto.getEvent_date())
|
||||||
|
.append("','")
|
||||||
|
.append(dto.getEvent_payload())
|
||||||
|
.append("'),\n"));
|
||||||
|
|
||||||
|
builder.replace(builder.length() - 2, builder.length(), ";");
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ############################################### SQL #######################################
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package mops.gruppen2.domain.service.helper;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.event.Event;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liefert verschiedene Projektionen auf Gruppen.
|
||||||
|
* Benötigt ausschließlich den EventStoreService.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class ProjectionHelper {
|
||||||
|
|
||||||
|
public static List<Group> project(List<Event> events) {
|
||||||
|
Map<UUID, Group> groups = new HashMap<>();
|
||||||
|
|
||||||
|
if (events.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace(groups);
|
||||||
|
log.trace(events);
|
||||||
|
|
||||||
|
events.forEach(event -> event.apply(getOrCreateGroup(groups, event.getGroupid())));
|
||||||
|
|
||||||
|
return new ArrayList<>(groups.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void project(Map<UUID, Group> groups, List<Event> events, GroupCache cache) {
|
||||||
|
if (events.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace(groups);
|
||||||
|
log.trace(events);
|
||||||
|
|
||||||
|
events.forEach(event -> event.apply(getOrCreateGroup(groups, event.getGroupid()), cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die Gruppe mit der richtigen Id aus der übergebenen Map wieder, existiert diese nicht
|
||||||
|
* wird die Gruppe erstellt und der Map hizugefügt.
|
||||||
|
*
|
||||||
|
* @param groups Map aus GruppenIds und Gruppen
|
||||||
|
* @param groupId Die Id der Gruppe, die zurückgegeben werden soll
|
||||||
|
*
|
||||||
|
* @return Die gesuchte Gruppe
|
||||||
|
*/
|
||||||
|
private static Group getOrCreateGroup(Map<UUID, Group> groups, UUID groupId) {
|
||||||
|
if (!groups.containsKey(groupId)) {
|
||||||
|
groups.put(groupId, Group.EMPTY());
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups.get(groupId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package mops.gruppen2.domain.service.helper;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import mops.gruppen2.domain.model.group.Membership;
|
||||||
|
import mops.gruppen2.domain.model.group.Role;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class SortHelper {
|
||||||
|
|
||||||
|
public static List<Membership> sortByMemberRole(List<Membership> memberships) {
|
||||||
|
memberships.sort((Membership m1, Membership m2) -> {
|
||||||
|
if (m1.getRole() == Role.ADMIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (m2.getRole() == Role.ADMIN) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return memberships;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package mops.gruppen2.domain.service.helper;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
|
import mops.gruppen2.domain.exception.GroupFullException;
|
||||||
|
import mops.gruppen2.domain.exception.LastAdminException;
|
||||||
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
|
import mops.gruppen2.domain.exception.UserExistsException;
|
||||||
|
import mops.gruppen2.domain.exception.UserNotFoundException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class ValidationHelper {
|
||||||
|
|
||||||
|
public static boolean checkIfLastMember(Group group, String userid) {
|
||||||
|
return group.isMember(userid) && group.size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Überprüft, ob ein User in einer Gruppe Admin ist.
|
||||||
|
*/
|
||||||
|
public static boolean checkIfAdmin(Group group, String userid) {
|
||||||
|
if (group.isMember(userid)) {
|
||||||
|
return group.isAdmin(userid);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkIfLastAdmin(Group group, String userid) {
|
||||||
|
return checkIfAdmin(group, userid) && group.getAdmins().size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################## THROW ############################################
|
||||||
|
|
||||||
|
|
||||||
|
public static void throwIfMember(Group group, String userid) throws UserExistsException {
|
||||||
|
if (group.isMember(userid)) {
|
||||||
|
log.error("Benutzer {} ist schon in Gruppe {}", userid, group);
|
||||||
|
throw new UserExistsException(userid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwIfNoMember(Group group, String userid) throws UserNotFoundException {
|
||||||
|
if (!group.isMember(userid)) {
|
||||||
|
log.error("Benutzer {} ist nicht in Gruppe {}!", userid, group);
|
||||||
|
throw new UserNotFoundException(userid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwIfNoAdmin(Group group, String userid) throws NoAccessException {
|
||||||
|
if (!checkIfAdmin(group, userid)) {
|
||||||
|
log.error("User {} ist kein Admin in Gruppe {}!", userid, group);
|
||||||
|
throw new NoAccessException(group.getId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schmeißt keine Exception, wenn der User der letzte User ist.
|
||||||
|
*/
|
||||||
|
public static void throwIfLastAdmin(Group group, String userid) throws LastAdminException {
|
||||||
|
if (!checkIfLastMember(group, userid) && checkIfLastAdmin(group, userid)) {
|
||||||
|
throw new LastAdminException("Du bist letzter Admin!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwIfGroupFull(Group group) throws GroupFullException {
|
||||||
|
if (group.isFull()) {
|
||||||
|
log.error("Die Gruppe {} ist voll!", group);
|
||||||
|
throw new GroupFullException(group.getId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateCreateForm(KeycloakAuthenticationToken token, Type type) {
|
||||||
|
if (!token.getAccount().getRoles().contains("orga") && type == Type.LECTURE) {
|
||||||
|
throw new BadArgumentException("Nur Orga kann Veranstaltungen erstellen.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package mops.gruppen2.infrastructure;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component
|
||||||
|
public class ApplicationInit {
|
||||||
|
|
||||||
|
private final GroupCache groupCache;
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void init() {
|
||||||
|
groupCache.init();
|
||||||
|
}
|
||||||
|
}
|
208
src/main/java/mops/gruppen2/infrastructure/GroupCache.java
Normal file
208
src/main/java/mops/gruppen2/infrastructure/GroupCache.java
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
package mops.gruppen2.infrastructure;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.GroupNotFoundException;
|
||||||
|
import mops.gruppen2.domain.exception.IdMismatchException;
|
||||||
|
import mops.gruppen2.domain.exception.UserNotFoundException;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.domain.service.EventStoreService;
|
||||||
|
import mops.gruppen2.domain.service.helper.ProjectionHelper;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached alle existierenden Gruppen und einige Beziehungen.
|
||||||
|
* Gruppen können nach Typ angefragt werden, nach ID, nach Link oder nach User.
|
||||||
|
* Der Cache wird von den Events aktualisiert.
|
||||||
|
* Beim Aufruf der init() Methode werden alle bisherigen Events projiziert und die Gruppen gespeichert.
|
||||||
|
* Die Komplette Anwendung verwendet eine Instanz des Caches.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component
|
||||||
|
@Scope("singleton")
|
||||||
|
public class GroupCache {
|
||||||
|
|
||||||
|
private final EventStoreService eventStoreService;
|
||||||
|
|
||||||
|
private final Map<UUID, Group> groups = new HashMap<>();
|
||||||
|
private final Map<String, Group> links = new HashMap<>();
|
||||||
|
private final Map<String, List<Group>> users = new HashMap<>(); // Wird vielleicht zu groß?
|
||||||
|
private final Map<Type, List<Group>> types = new EnumMap<>(Type.class);
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################## CACHE ###########################################
|
||||||
|
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
ProjectionHelper.project(groups, eventStoreService.findAllEvents(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ########################################### GETTERS #######################################
|
||||||
|
|
||||||
|
|
||||||
|
public Group group(UUID groupid) {
|
||||||
|
if (!groups.containsKey(groupid)) {
|
||||||
|
throw new GroupNotFoundException("Gruppe ist nicht im Cache.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups.get(groupid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Group group(String link) {
|
||||||
|
if (!links.containsKey(link)) {
|
||||||
|
throw new GroupNotFoundException("Link ist nicht im Cache.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return links.get(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> groups() {
|
||||||
|
if (groups.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return List.copyOf(groups.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> userGroups(String userid) {
|
||||||
|
if (!users.containsKey(userid)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(users.get(userid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> userLectures(String userid) {
|
||||||
|
return userGroups(userid).stream()
|
||||||
|
.filter(Group::isLecture)
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> userPublics(String userid) {
|
||||||
|
return userGroups(userid).stream()
|
||||||
|
.filter(Group::isPublic)
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> userPrivates(String userid) {
|
||||||
|
return userGroups(userid).stream()
|
||||||
|
.filter(Group::isPrivate)
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> publics() {
|
||||||
|
if (!types.containsKey(Type.PUBLIC)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(types.get(Type.PUBLIC));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> privates() {
|
||||||
|
if (!types.containsKey(Type.PRIVATE)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(types.get(Type.PRIVATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> lectures() {
|
||||||
|
if (!types.containsKey(Type.LECTURE)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(types.get(Type.LECTURE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ######################################## SETTERS ##########################################
|
||||||
|
|
||||||
|
|
||||||
|
public void usersPut(String userid, Group group) {
|
||||||
|
if (!group.isMember(userid)) {
|
||||||
|
throw new UserNotFoundException("User ist kein Mitglied, Gruppe nicht gecached.");
|
||||||
|
}
|
||||||
|
if (!users.containsKey(userid)) {
|
||||||
|
users.put(userid, new ArrayList<>());
|
||||||
|
log.debug("Ein User wurde dem Cache hinzugefügt.");
|
||||||
|
}
|
||||||
|
|
||||||
|
users.get(userid).add(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void usersRemove(String target, Group group) {
|
||||||
|
if (!users.containsKey(target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
users.get(target).remove(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void groupsPut(UUID groupid, Group group) {
|
||||||
|
if (group.getId() != groupid) {
|
||||||
|
throw new IdMismatchException("ID passt nicht zu Gruppe, Gruppe nicht gecached.");
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.put(groupid, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void groupsRemove(UUID groupid, Group group) {
|
||||||
|
if (!groups.containsKey(groupid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.remove(groupid);
|
||||||
|
links.remove(group.getLink());
|
||||||
|
group.getMembers().forEach(user -> users.get(user.getId()).removeIf(usergroup -> !usergroup.exists()));
|
||||||
|
types.get(group.getType()).removeIf(typegroup -> !typegroup.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void linksPut(String link, Group group) {
|
||||||
|
if (!link.equals(group.getLink())) {
|
||||||
|
throw new IdMismatchException("Link passt nicht zu Gruppe, Gruppe nicht gecached.");
|
||||||
|
}
|
||||||
|
|
||||||
|
links.put(link, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void linksRemove(String link) {
|
||||||
|
if (!links.containsKey(link)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
links.remove(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void typesPut(Type type, Group group) {
|
||||||
|
if (!types.containsKey(type)) {
|
||||||
|
types.put(type, new ArrayList<>());
|
||||||
|
log.debug("Ein Typ wurde dem Cache hinzugefügt.");
|
||||||
|
}
|
||||||
|
if (group.getType() != type) {
|
||||||
|
throw new IdMismatchException("Typ passt nicht zu Gruppe, Gruppe nicht gecached.");
|
||||||
|
}
|
||||||
|
|
||||||
|
types.get(type).add(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void typesRemove(Type type, Group group) {
|
||||||
|
if (!types.containsKey(type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
types.get(type).remove(group);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package mops.gruppen2.infrastructure;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import mops.gruppen2.domain.Account;
|
||||||
|
import mops.gruppen2.domain.model.group.Role;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ControllerAdvice
|
||||||
|
public class ModelAttributeControllerAdvice {
|
||||||
|
|
||||||
|
// Add modelAttributes before each @RequestMapping
|
||||||
|
@ModelAttribute
|
||||||
|
public void modelAttributes(KeycloakAuthenticationToken token,
|
||||||
|
Model model) {
|
||||||
|
|
||||||
|
// Prevent NullPointerException if not logged in
|
||||||
|
if (token != null) {
|
||||||
|
model.addAttribute("account", new Account(token));
|
||||||
|
model.addAttribute("principal", new User(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add enums
|
||||||
|
model.addAttribute("REGULAR", Role.REGULAR);
|
||||||
|
model.addAttribute("ADMIN", Role.ADMIN);
|
||||||
|
model.addAttribute("PUBLIC", Type.PUBLIC);
|
||||||
|
model.addAttribute("PRIVATE", Type.PRIVATE);
|
||||||
|
model.addAttribute("LECTURE", Type.LECTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,18 +1,17 @@
|
|||||||
package mops.gruppen2.domain.api;
|
package mops.gruppen2.infrastructure.api;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import mops.gruppen2.domain.Group;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kombiniert den Status und die Gruppenliste zur ausgabe über die API.
|
* Kombiniert den Status und die Gruppenliste zur ausgabe über die API.
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
public class GroupRequestWrapper {
|
public class GroupRequestWrapper {
|
||||||
|
|
||||||
private final Long status;
|
private final long version;
|
||||||
private final List<Group> groupList;
|
private final List<GroupWrapper> groups;
|
||||||
}
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package mops.gruppen2.infrastructure.api;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class GroupWrapper {
|
||||||
|
|
||||||
|
UUID groupid;
|
||||||
|
Type type;
|
||||||
|
UUID parent;
|
||||||
|
String title;
|
||||||
|
String description;
|
||||||
|
List<User> admins;
|
||||||
|
List<User> regulars;
|
||||||
|
|
||||||
|
public GroupWrapper(Group group) {
|
||||||
|
groupid = group.getId();
|
||||||
|
type = group.getType();
|
||||||
|
parent = group.getParent();
|
||||||
|
title = group.getTitle();
|
||||||
|
description = group.getDescription();
|
||||||
|
admins = group.getAdmins();
|
||||||
|
regulars = group.getRegulars();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package mops.gruppen2.infrastructure.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.service.EventStoreService;
|
||||||
|
import mops.gruppen2.domain.service.helper.APIHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.ProjectionHelper;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Api zum Datenabgleich.
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@TraceMethodCalls
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/gruppen2/api")
|
||||||
|
public class APIController {
|
||||||
|
|
||||||
|
private final GroupCache cache;
|
||||||
|
private final EventStoreService eventStoreService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt eine Liste aus Gruppen, welche sich seit einer übergebenen Event-Id geändert haben.
|
||||||
|
* Die Gruppen werden vollständig projiziert, enthalten also alle Informationen zum entsprechenden Zeitpunkt.
|
||||||
|
*
|
||||||
|
* @param eventId Die Event-ID, welche der Anfragesteller beim letzten Aufruf erhalten hat
|
||||||
|
*/
|
||||||
|
//TODO: sollte den cache benutzen, am besten wäre eine groupversion, welche der eventid
|
||||||
|
//TODO: entspricht, dann kann man leicht alle geänderten gruppen finden
|
||||||
|
@GetMapping("/update/{id}")
|
||||||
|
@Secured("ROLE_api_user")
|
||||||
|
@ApiOperation("Gibt veränderte Gruppen zurück")
|
||||||
|
public GroupRequestWrapper getApiUpdate(@ApiParam("Letzte gespeicherte EventId des Anfragestellers")
|
||||||
|
@PathVariable("id") long eventId) {
|
||||||
|
|
||||||
|
return APIHelper.wrap(eventStoreService.findMaxEventId(),
|
||||||
|
ProjectionHelper.project(eventStoreService.findGroupEvents(eventStoreService.findChangedGroups(eventId))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die Gruppen-IDs von Gruppen, in welchen der übergebene Nutzer teilnimmt, zurück.
|
||||||
|
*/
|
||||||
|
@GetMapping("/usergroups/{id}")
|
||||||
|
@Secured("ROLE_api_user")
|
||||||
|
@ApiOperation("Gibt Gruppen zurück, in welchen ein Nutzer teilnimmt")
|
||||||
|
public List<String> getApiUserGroups(@ApiParam("Nutzer-Id")
|
||||||
|
@PathVariable("id") String userId) {
|
||||||
|
|
||||||
|
return cache.userGroups(userId).stream()
|
||||||
|
.map(Group::getId)
|
||||||
|
.map(UUID::toString)
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Konstruiert eine einzelne, vollständige Gruppe.
|
||||||
|
*/
|
||||||
|
@GetMapping("/group/{id}")
|
||||||
|
@Secured("ROLE_api_user")
|
||||||
|
@ApiOperation("Gibt die Gruppe mit der als Parameter mitgegebenden groupId zurück")
|
||||||
|
public Group getApiGroup(@ApiParam("Gruppen-Id der gefordeten Gruppe")
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
return cache.group(UUID.fromString(groupId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package mops.gruppen2.infrastructure.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
|
import mops.gruppen2.domain.service.GroupService;
|
||||||
|
import mops.gruppen2.domain.service.helper.FileHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.security.RolesAllowed;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
@SuppressWarnings("SameReturnValue")
|
||||||
|
@Log4j2
|
||||||
|
@TraceMethodCalls
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/gruppen2")
|
||||||
|
public class GroupCreationController {
|
||||||
|
|
||||||
|
private final GroupCache groupCache;
|
||||||
|
private final GroupService groupService;
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping("/create")
|
||||||
|
public String getCreate(Model model) {
|
||||||
|
|
||||||
|
model.addAttribute("lectures", groupCache.lectures());
|
||||||
|
|
||||||
|
return "create";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/create")
|
||||||
|
public String postCreateOrga(KeycloakAuthenticationToken token,
|
||||||
|
@RequestParam("type") Type type,
|
||||||
|
@RequestParam("parent") @Valid Parent parent,
|
||||||
|
@RequestParam("title") @Valid Title title,
|
||||||
|
@RequestParam("description") @Valid Description description,
|
||||||
|
@RequestParam("limit") @Valid Limit limit,
|
||||||
|
@RequestParam(value = "file", required = false) MultipartFile file) {
|
||||||
|
|
||||||
|
// Zusätzlicher check: studentin kann keine lecture erstellen
|
||||||
|
ValidationHelper.validateCreateForm(token, type);
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupService.createGroup(principal);
|
||||||
|
groupService.initGroupMembers(group, principal, principal, new User(token), limit);
|
||||||
|
groupService.initGroupMeta(group, principal, type, parent);
|
||||||
|
groupService.initGroupText(group, principal, title, description);
|
||||||
|
|
||||||
|
// ROLE_studentin kann kein CSV importieren
|
||||||
|
if (token.getAccount().getRoles().contains("orga")) {
|
||||||
|
groupService.addUsersToGroup(group, principal, FileHelper.readCsvFile(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + group.getId();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,296 @@
|
|||||||
|
package mops.gruppen2.infrastructure.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
|
import mops.gruppen2.domain.model.group.User;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
|
import mops.gruppen2.domain.service.EventStoreService;
|
||||||
|
import mops.gruppen2.domain.service.GroupService;
|
||||||
|
import mops.gruppen2.domain.service.helper.FileHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.security.RolesAllowed;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@SuppressWarnings("SameReturnValue")
|
||||||
|
@Log4j2
|
||||||
|
@TraceMethodCalls
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/gruppen2")
|
||||||
|
public class GroupDetailsController {
|
||||||
|
|
||||||
|
private final GroupCache groupCache;
|
||||||
|
private final GroupService groupService;
|
||||||
|
private final EventStoreService eventStoreService;
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping("/details/{id}")
|
||||||
|
public String getDetailsPage(KeycloakAuthenticationToken token,
|
||||||
|
Model model,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
// Parent Badge
|
||||||
|
Group parent = Group.EMPTY();
|
||||||
|
if (group.hasParent()) {
|
||||||
|
parent = groupCache.group(group.getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addAttribute("group", group);
|
||||||
|
model.addAttribute("parent", parent);
|
||||||
|
|
||||||
|
// Detailseite für nicht-Mitglieder
|
||||||
|
if (!group.isMember(principal)) {
|
||||||
|
return "preview";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "details";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/join")
|
||||||
|
public String postDetailsJoin(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
if (group.isMember(principal)) {
|
||||||
|
return "redirect:/gruppen2/details/" + groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
groupService.addMember(group, principal, principal, new User(token));
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/leave")
|
||||||
|
public String postDetailsLeave(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
groupService.kickMember(group, principal, principal);
|
||||||
|
|
||||||
|
return "redirect:/gruppen2";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping("details/{id}/history")
|
||||||
|
public String getDetailsHistory(KeycloakAuthenticationToken token,
|
||||||
|
Model model,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
model.addAttribute("events",
|
||||||
|
eventStoreService.findGroupEvents(UUID.fromString(groupId)));
|
||||||
|
|
||||||
|
return "log";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping(value = "details/{id}/export/history/plain", produces = "text/plain;charset=UTF-8")
|
||||||
|
public void getDetailsExportHistoryPlain(HttpServletResponse response,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String filename = "eventlog-" + groupId + ".txt";
|
||||||
|
|
||||||
|
response.setContentType("text/txt;charset=UTF-8");
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + filename + "\"");
|
||||||
|
|
||||||
|
try {
|
||||||
|
response.getWriter()
|
||||||
|
.write(FileHelper.payloadsToPlain(
|
||||||
|
eventStoreService.findGroupPayloads(UUID.fromString(groupId))));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Payloads konnten nicht geschrieben werden.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping(value = "details/{id}/export/history/sql", produces = "application/sql;charset=UTF-8")
|
||||||
|
public void getDetailsExportHistorySql(HttpServletResponse response,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String filename = "data.sql";
|
||||||
|
|
||||||
|
response.setContentType("application/sql;charset=UTF-8");
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + filename + "\"");
|
||||||
|
|
||||||
|
try {
|
||||||
|
response.getWriter()
|
||||||
|
.write(FileHelper.eventDTOsToSql(
|
||||||
|
eventStoreService.findGroupDTOs(UUID.fromString(groupId))));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Payloads konnten nicht geschrieben werden.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping(value = "details/{id}/export/members", produces = "text/csv;charset=UTF-8")
|
||||||
|
public void getDetailsExportMembers(HttpServletResponse response,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String filename = "teilnehmer-" + groupId + ".csv";
|
||||||
|
|
||||||
|
response.setContentType("text/csv;charset=UTF-8");
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + filename + "\"");
|
||||||
|
|
||||||
|
try {
|
||||||
|
response.getWriter()
|
||||||
|
.print(FileHelper.writeCsvUserList(groupCache.group(UUID.fromString(groupId)).getMembers()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Teilnehmerliste konnte nicht geschrieben werden.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@GetMapping("/details/{id}/edit")
|
||||||
|
public String getDetailsEdit(KeycloakAuthenticationToken token,
|
||||||
|
Model model,
|
||||||
|
HttpServletRequest request,
|
||||||
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
// Invite Link
|
||||||
|
String actualURL = request.getRequestURL().toString();
|
||||||
|
String serverURL = actualURL.substring(0, actualURL.indexOf("gruppen2/"));
|
||||||
|
String link = serverURL + "gruppen2/join/" + group.getLink();
|
||||||
|
|
||||||
|
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||||
|
|
||||||
|
model.addAttribute("group", group);
|
||||||
|
model.addAttribute("link", link);
|
||||||
|
|
||||||
|
return "edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/edit/meta")
|
||||||
|
public String postDetailsEditMeta(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId,
|
||||||
|
@Valid Title title,
|
||||||
|
@Valid Description description) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
groupService.setTitle(group, principal, title);
|
||||||
|
groupService.setDescription(group, principal, description);
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/edit/userlimit")
|
||||||
|
public String postDetailsEditUserLimit(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId,
|
||||||
|
@Valid Limit limit) {
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
groupService.setLimit(group, principal, limit);
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("ROLE_orga")
|
||||||
|
@PostMapping("/details/{id}/edit/csv")
|
||||||
|
public String postDetailsEditCsv(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId,
|
||||||
|
@RequestParam(value = "file", required = false) MultipartFile file) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
groupService.addUsersToGroup(group, principal, FileHelper.readCsvFile(file));
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/edit/role/{userid}")
|
||||||
|
public String postDetailsEditRole(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId,
|
||||||
|
@PathVariable("userid") String target) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||||
|
if (target.equals(principal)) {
|
||||||
|
ValidationHelper.throwIfLastAdmin(group, principal);
|
||||||
|
}
|
||||||
|
|
||||||
|
groupService.toggleMemberRole(group, principal, target);
|
||||||
|
|
||||||
|
// Falls sich der User selbst die Rechte genommen hat
|
||||||
|
if (!ValidationHelper.checkIfAdmin(group, principal)) {
|
||||||
|
return "redirect:/gruppen2/details/" + groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/edit/delete/{userid}")
|
||||||
|
public String postDetailsEditDelete(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupId,
|
||||||
|
@PathVariable("userid") String target) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
|
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||||
|
|
||||||
|
// Der eingeloggte User kann sich nicht selbst entfernen (er kann aber verlassen)
|
||||||
|
if (!principal.equals(target)) {
|
||||||
|
groupService.kickMember(group, principal, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
|
@PostMapping("/details/{id}/edit/destroy")
|
||||||
|
public String postDetailsEditDestroy(KeycloakAuthenticationToken token,
|
||||||
|
@PathVariable("id") String groupid) {
|
||||||
|
|
||||||
|
String principal = token.getName();
|
||||||
|
Group group = groupCache.group(UUID.fromString(groupid));
|
||||||
|
|
||||||
|
groupService.deleteGroup(group, principal);
|
||||||
|
|
||||||
|
return "redirect:/gruppen2";
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Method + view for /details/{id}/member/{id}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package mops.gruppen2.controller;
|
package mops.gruppen2.infrastructure.controller;
|
||||||
|
|
||||||
import mops.gruppen2.domain.Account;
|
import lombok.RequiredArgsConstructor;
|
||||||
import mops.gruppen2.domain.User;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.aspect.annotation.TraceMethodCall;
|
||||||
import mops.gruppen2.domain.exception.PageNotFoundException;
|
import mops.gruppen2.domain.exception.PageNotFoundException;
|
||||||
import mops.gruppen2.service.KeyCloakService;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
import mops.gruppen2.service.UserService;
|
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
@ -14,31 +14,29 @@ import javax.annotation.security.RolesAllowed;
|
|||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@SuppressWarnings("SameReturnValue")
|
||||||
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
@Controller
|
@Controller
|
||||||
public class GruppenfindungController {
|
public class GruppenfindungController {
|
||||||
|
|
||||||
private final UserService userService;
|
private final GroupCache groupCache;
|
||||||
|
|
||||||
public GruppenfindungController(UserService userService) {
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// For convenience
|
||||||
@GetMapping("")
|
@GetMapping("")
|
||||||
public String redirect() {
|
public String redirect() {
|
||||||
return "redirect:/gruppen2";
|
return "redirect:/gruppen2";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
|
@TraceMethodCall
|
||||||
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
@GetMapping("/gruppen2")
|
@GetMapping("/gruppen2")
|
||||||
public String index(KeycloakAuthenticationToken token,
|
public String getIndexPage(KeycloakAuthenticationToken token,
|
||||||
Model model) {
|
Model model) {
|
||||||
|
|
||||||
Account account = KeyCloakService.createAccountFromPrincipal(token);
|
model.addAttribute("lectures", groupCache.userLectures(token.getName()));
|
||||||
User user = new User(account);
|
model.addAttribute("publics", groupCache.userPublics(token.getName()));
|
||||||
|
model.addAttribute("privates", groupCache.userPrivates(token.getName()));
|
||||||
model.addAttribute("account", account);
|
|
||||||
model.addAttribute("gruppen", userService.getUserGroups(user));
|
|
||||||
model.addAttribute("user", user);
|
|
||||||
|
|
||||||
return "index";
|
return "index";
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user