diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 93e8b85..bdc24da 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -59,7 +59,20 @@ "Bash(mkdir -p /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/games/common/repository)", "Bash(mkdir -p /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben)", "Bash(mkdir -p /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/entity)", - "Bash(mkdir -p /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/repository)" + "Bash(mkdir -p /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/repository)", + "Bash(grep -l \"script>\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/*.html)", + "Bash(./gradlew compileJava -q)", + "Bash(do)", + "Bash(echo \"=== $f ===\")", + "Read(//home/mario/Workspaces/xxx-thegame/.claude/worktrees/agent-a211ce07/**)", + "Bash(./gradlew :xxxthegame:compileJava -q)", + "Bash(uniq done:*)", + "Bash(mv aufgaben.html games/bdsm/)", + "Bash(mv bdsm.html games/bdsm/)", + "Bash(mv bdsm-einladung.html games/bdsm/)", + "Bash(mv bdsmingame.html games/bdsm/)", + "Bash(mv bdsmplayers.html games/bdsm/)", + "Bash(perl -pi -e 's|\\\\.requestMatchers\\\\\\(\"\"/\\\\*\\\\.html\"\"\\\\\\)\\\\.permitAll\\\\\\(\\\\\\)|.requestMatchers\\(\"\"/*.html\"\"\\).permitAll\\(\\)\\\\n .requestMatchers\\(\"\"/**/*.html\"\"\\).permitAll\\(\\)|' /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/config/SecurityConfig.java)" ] } } diff --git a/.claude/worktrees/agent-a211ce07 b/.claude/worktrees/agent-a211ce07 new file mode 160000 index 0000000..e262a1b --- /dev/null +++ b/.claude/worktrees/agent-a211ce07 @@ -0,0 +1 @@ +Subproject commit e262a1b46b60f613d7582ef76db82a8069263f31 diff --git a/.metadata/.lock_info b/.metadata/.lock_info index b8486e5..bdf34f0 100644 --- a/.metadata/.lock_info +++ b/.metadata/.lock_info @@ -1,5 +1,5 @@ -#Fri Mar 27 07:46:21 CET 2026 +#Sun Mar 29 16:28:09 CEST 2026 display=\:0 host=mario-mint -process-id=5726 +process-id=3723 user=mario diff --git a/.metadata/.log b/.metadata/.log index b208bc1..e4ad0f9 100644 --- a/.metadata/.log +++ b/.metadata/.log @@ -1172,3 +1172,166 @@ java.lang.NullPointerException: Cannot invoke "org.eclipse.jdt.internal.compiler at org.eclipse.jdt.internal.ui.util.SelectionUtil.logException(SelectionUtil.java:157) at org.eclipse.jdt.internal.ui.text.java.hover.AbstractJavaEditorTextHover.getJavaElementsAt(AbstractJavaEditorTextHover.java:124) ... 14 more + +!ENTRY org.springframework.tooling.boot.ls 1 0 2026-03-27 12:09:57.934 +!MESSAGE DelegatingStreamConnectionProvider - Stopping Boot LS +!SESSION 2026-03-29 16:28:05.532 ----------------------------------------------- +eclipse.buildId=4.39.0.20260305-0817 +java.version=21.0.6 +java.vendor=Eclipse Adoptium +BootLoader constants: OS=linux, ARCH=x86_64, WS=gtk, NL=de_DE +Framework arguments: -product org.eclipse.epp.package.java.product +Command-line arguments: -os linux -ws gtk -arch x86_64 -clean -product org.eclipse.epp.package.java.product + +!ENTRY ch.qos.logback.classic 1 0 2026-03-29 16:28:07.076 +!MESSAGE Activated before the state location was initialized. Retry after the state location is initialized. + +!ENTRY ch.qos.logback.classic 1 0 2026-03-29 16:28:10.040 +!MESSAGE Logback config file: /home/mario/Workspaces/xxx-thegame/.metadata/.plugins/org.eclipse.m2e.logback/logback.2.7.101.20251017-1242.xml + +!ENTRY org.eclipse.ui 2 0 2026-03-29 16:28:10.201 +!MESSAGE Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points. +!SUBENTRY 1 org.eclipse.ui 2 0 2026-03-29 16:28:10.201 +!MESSAGE Commands should really have a category: plug-in='org.springframework.tooling.boot.ls', id='spring.initializr.addStarters', categoryId='org.eclipse.lsp4e.commandCategory' + +!ENTRY org.eclipse.ui 2 0 2026-03-29 16:28:10.332 +!MESSAGE Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points. +!SUBENTRY 1 org.eclipse.ui 2 0 2026-03-29 16:28:10.332 +!MESSAGE Commands should really have a category: plug-in='org.springframework.tooling.boot.ls', id='spring.initializr.addStarters', categoryId='org.eclipse.lsp4e.commandCategory' + +!ENTRY org.eclipse.jface 2 0 2026-03-29 17:27:01.590 +!MESSAGE Keybinding conflicts occurred. They may interfere with normal accelerator operation. +!SUBENTRY 1 org.eclipse.jface 2 0 2026-03-29 17:27:01.590 +!MESSAGE A conflict occurred for CTRL+SHIFT+T: +Binding(CTRL+SHIFT+T, + ParameterizedCommand(Command(org.eclipse.jdt.ui.navigate.open.type,Open Type, + Open a type in a Java editor, + Category(org.eclipse.ui.category.navigate,Navigate,null,true), + WorkbenchHandlerServiceHandler("org.eclipse.jdt.ui.navigate.open.type"), + ,,true),null), + org.eclipse.ui.defaultAcceleratorConfiguration, + org.eclipse.ui.contexts.window,,,system) +Binding(CTRL+SHIFT+T, + ParameterizedCommand(Command(org.eclipse.lsp4e.symbolInWorkspace,Go to Symbol in Workspace, + , + Category(org.eclipse.lsp4e.category,Language Servers,null,true), + WorkbenchHandlerServiceHandler("org.eclipse.lsp4e.symbolInWorkspace"), + ,,true),null), + org.eclipse.ui.defaultAcceleratorConfiguration, + org.eclipse.ui.contexts.window,,,system) + +!ENTRY org.eclipse.jdt.ui 4 10001 2026-03-29 17:41:39.966 +!MESSAGE Internal Error +!STACK 1 +Java Model Exception: Error in Java Model (code 969): toMitspielerBdsm(VanillaMitspieler) {key=Lde/oaa/xxx/games/vanilla/VanillaGameDurchfuehren;.toMitspielerBdsm(Lde/oaa/xxx/games/vanilla/VanillaMitspieler;)Lde/oaa/xxx/games/bdsm/BdsmMitspieler;} [in VanillaGameDurchfuehren [in [Working copy] VanillaGameDurchfuehren.java [in de.oaa.xxx.games.vanilla [in src/main/java [in xxxthegame]]]]] does not exist + at org.eclipse.jdt.internal.core.JavaElement.newNotPresentException(JavaElement.java:548) + at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:591) + at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:294) + at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:280) + at org.eclipse.jdt.internal.core.Member.getFlags(Member.java:193) + at org.eclipse.jdt.internal.corext.util.JdtFlags.isPrivate(JdtFlags.java:157) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkSuperImplementationDetector.isOverriddenMethod(JavaElementHyperlinkSuperImplementationDetector.java:57) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkSuperImplementationDetector.addHyperlinks(JavaElementHyperlinkSuperImplementationDetector.java:44) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector.detectHyperlinksCached(JavaElementHyperlinkDetector.java:139) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector.lambda$0(JavaElementHyperlinkDetector.java:84) + at org.eclipse.jdt.internal.core.JavaModelManager.cacheZipFiles(JavaModelManager.java:5709) + at org.eclipse.jdt.internal.core.JavaModelManager.callReadOnly(JavaModelManager.java:5698) + at org.eclipse.jdt.core.JavaCore.callReadOnly(JavaCore.java:6211) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector.detectHyperlinks(JavaElementHyperlinkDetector.java:84) + at org.eclipse.ui.texteditor.HyperlinkDetectorRegistry$HyperlinkDetectorDelegate.detectHyperlinks(HyperlinkDetectorRegistry.java:83) + at org.eclipse.jface.text.hyperlink.HyperlinkManager.findHyperlinks(HyperlinkManager.java:294) + at org.eclipse.jface.text.hyperlink.HyperlinkManager.findHyperlinks(HyperlinkManager.java:264) + at org.eclipse.jface.text.hyperlink.HyperlinkManager.mouseMove(HyperlinkManager.java:474) + at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:254) + at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:91) + at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5845) + at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1656) + at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:5060) + at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4497) + at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1160) + at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339) + at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1051) + at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153) + at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:684) + at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339) + at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583) + at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173) + at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185) + at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219) + at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149) + at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115) + at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467) + at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:615) + at org.eclipse.equinox.launcher.Main.basicRun(Main.java:563) + at org.eclipse.equinox.launcher.Main.run(Main.java:1415) + at org.eclipse.equinox.launcher.Main.main(Main.java:1387) +!SUBENTRY 1 org.eclipse.jdt.core 4 969 2026-03-29 17:41:39.967 +!MESSAGE toMitspielerBdsm(VanillaMitspieler) {key=Lde/oaa/xxx/games/vanilla/VanillaGameDurchfuehren;.toMitspielerBdsm(Lde/oaa/xxx/games/vanilla/VanillaMitspieler;)Lde/oaa/xxx/games/bdsm/BdsmMitspieler;} [in VanillaGameDurchfuehren [in [Working copy] VanillaGameDurchfuehren.java [in de.oaa.xxx.games.vanilla [in src/main/java [in xxxthegame]]]]] does not exist + +!ENTRY org.eclipse.jdt.ui 4 10001 2026-03-29 17:41:39.968 +!MESSAGE Internal Error +!STACK 1 +Java Model Exception: Error in Java Model (code 969): toMitspielerBdsm(VanillaMitspieler) {key=Lde/oaa/xxx/games/vanilla/VanillaGameDurchfuehren;.toMitspielerBdsm(Lde/oaa/xxx/games/vanilla/VanillaMitspieler;)Lde/oaa/xxx/games/bdsm/BdsmMitspieler;} [in VanillaGameDurchfuehren [in [Working copy] VanillaGameDurchfuehren.java [in de.oaa.xxx.games.vanilla [in src/main/java [in xxxthegame]]]]] does not exist + at org.eclipse.jdt.internal.core.JavaElement.newNotPresentException(JavaElement.java:548) + at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:591) + at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:294) + at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:280) + at org.eclipse.jdt.internal.core.SourceMethod.getReturnType(SourceMethod.java:223) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkReturnTypeDetector.addHyperlinks(JavaElementHyperlinkReturnTypeDetector.java:43) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector.detectHyperlinksCached(JavaElementHyperlinkDetector.java:139) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector.lambda$0(JavaElementHyperlinkDetector.java:84) + at org.eclipse.jdt.internal.core.JavaModelManager.cacheZipFiles(JavaModelManager.java:5709) + at org.eclipse.jdt.internal.core.JavaModelManager.callReadOnly(JavaModelManager.java:5698) + at org.eclipse.jdt.core.JavaCore.callReadOnly(JavaCore.java:6211) + at org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector.detectHyperlinks(JavaElementHyperlinkDetector.java:84) + at org.eclipse.ui.texteditor.HyperlinkDetectorRegistry$HyperlinkDetectorDelegate.detectHyperlinks(HyperlinkDetectorRegistry.java:83) + at org.eclipse.jface.text.hyperlink.HyperlinkManager.findHyperlinks(HyperlinkManager.java:294) + at org.eclipse.jface.text.hyperlink.HyperlinkManager.findHyperlinks(HyperlinkManager.java:264) + at org.eclipse.jface.text.hyperlink.HyperlinkManager.mouseMove(HyperlinkManager.java:474) + at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:254) + at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:91) + at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5845) + at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1656) + at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:5060) + at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4497) + at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1160) + at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339) + at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1051) + at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153) + at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:684) + at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339) + at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583) + at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173) + at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185) + at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219) + at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149) + at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115) + at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467) + at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:615) + at org.eclipse.equinox.launcher.Main.basicRun(Main.java:563) + at org.eclipse.equinox.launcher.Main.run(Main.java:1415) + at org.eclipse.equinox.launcher.Main.main(Main.java:1387) +!SUBENTRY 1 org.eclipse.jdt.core 4 969 2026-03-29 17:41:39.969 +!MESSAGE toMitspielerBdsm(VanillaMitspieler) {key=Lde/oaa/xxx/games/vanilla/VanillaGameDurchfuehren;.toMitspielerBdsm(Lde/oaa/xxx/games/vanilla/VanillaMitspieler;)Lde/oaa/xxx/games/bdsm/BdsmMitspieler;} [in VanillaGameDurchfuehren [in [Working copy] VanillaGameDurchfuehren.java [in de.oaa.xxx.games.vanilla [in src/main/java [in xxxthegame]]]]] does not exist + +!ENTRY org.eclipse.debug.core 4 125 2026-03-29 21:26:35.374 +!MESSAGE Error logged from Debug Core: +!STACK 0 +java.io.IOException: Stream closed + at java.base/java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:188) + at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:343) + at java.base/java.io.BufferedInputStream.implRead(BufferedInputStream.java:420) + at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:405) + at java.base/java.io.FilterInputStream.read(FilterInputStream.java:95) + at org.eclipse.debug.internal.core.OutputStreamMonitor.internalRead(OutputStreamMonitor.java:235) + at org.eclipse.debug.internal.core.OutputStreamMonitor.read(OutputStreamMonitor.java:211) + at java.base/java.lang.Thread.run(Thread.java:1583) + +!ENTRY org.springframework.tooling.boot.ls 1 0 2026-03-29 22:58:21.587 +!MESSAGE DelegatingStreamConnectionProvider - Stopping Boot LS diff --git a/.metadata/.plugins/org.eclipse.buildship.core/gradle/versions.json b/.metadata/.plugins/org.eclipse.buildship.core/gradle/versions.json index 96eebdb..c47ab07 100644 --- a/.metadata/.plugins/org.eclipse.buildship.core/gradle/versions.json +++ b/.metadata/.plugins/org.eclipse.buildship.core/gradle/versions.json @@ -1,24 +1,7 @@ [ { - "version" : "9.5.0-20260326015913+0000", - "buildTime" : "20260326015913+0000", - "commitId" : "b62b56136fe3f28a01c3e35f77694c3d5af75916", - "current" : false, - "snapshot" : true, - "nightly" : false, - "releaseNightly" : true, - "activeRc" : false, - "rcFor" : "", - "milestoneFor" : "", - "broken" : false, - "downloadUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.5.0-20260326015913+0000-bin.zip", - "checksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.5.0-20260326015913+0000-bin.zip.sha256", - "checksum" : "ace6a98f3a565a82cd108c6a115f64837cd5bb8e95d563c6e2dfb884ea3a8fe5", - "wrapperChecksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.5.0-20260326015913+0000-wrapper.jar.sha256", - "wrapperChecksum" : "497c8c2a7e5031f6aa847f88104aa80a93532ec32ee17bdb8d1d2f67a194a9c7" -}, { - "version" : "9.6.0-20260326003843+0000", - "buildTime" : "20260326003843+0000", - "commitId" : "f6b5714b236ea05298517d966a339045da81a5ee", + "version" : "9.6.0-20260329003549+0000", + "buildTime" : "20260329003549+0000", + "commitId" : "db62c2f2b404217cb6a7eef2598c6e84ab08fa27", "current" : false, "snapshot" : true, "nightly" : true, @@ -27,11 +10,28 @@ "rcFor" : "", "milestoneFor" : "", "broken" : false, - "downloadUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.6.0-20260326003843+0000-bin.zip", - "checksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.6.0-20260326003843+0000-bin.zip.sha256", - "checksum" : "9d70bda347d4cdbc4fc8ce8550d53ce5d1b2add847f4720e8543ff6c74c322b8", - "wrapperChecksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.6.0-20260326003843+0000-wrapper.jar.sha256", - "wrapperChecksum" : "f307680272dffdb8e636f1169adfbf693513005c80aa06e8d381f20390a06e6a" + "downloadUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.6.0-20260329003549+0000-bin.zip", + "checksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.6.0-20260329003549+0000-bin.zip.sha256", + "checksum" : "27b9c08aeaf720b9ee44dc6eef5543699bafba27772aa8a33e64cf964a2ea958", + "wrapperChecksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.6.0-20260329003549+0000-wrapper.jar.sha256", + "wrapperChecksum" : "497c8c2a7e5031f6aa847f88104aa80a93532ec32ee17bdb8d1d2f67a194a9c7" +}, { + "version" : "9.5.0-20260328024422+0000", + "buildTime" : "20260328024422+0000", + "commitId" : "a90300e5c547f6d0416d765f1ef285d1ecb589f9", + "current" : false, + "snapshot" : true, + "nightly" : false, + "releaseNightly" : true, + "activeRc" : false, + "rcFor" : "", + "milestoneFor" : "", + "broken" : false, + "downloadUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.5.0-20260328024422+0000-bin.zip", + "checksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.5.0-20260328024422+0000-bin.zip.sha256", + "checksum" : "f921ed9b701b2046ba53c3c499df12ebab7b70b6d58c83337d9375427f9af2ee", + "wrapperChecksumUrl" : "https://services.gradle.org/distributions-snapshots/gradle-9.5.0-20260328024422+0000-wrapper.jar.sha256", + "wrapperChecksum" : "497c8c2a7e5031f6aa847f88104aa80a93532ec32ee17bdb8d1d2f67a194a9c7" }, { "version" : "9.4.1", "buildTime" : "20260319084628+0000", diff --git a/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources b/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources index b78f501..27851be 100644 Binary files a/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources and b/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources differ diff --git a/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi b/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi index 47190fd..cb699f1 100644 --- a/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi +++ b/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi @@ -1,8 +1,8 @@ - - + + activeSchemeId:org.eclipse.ui.defaultAcceleratorConfiguration - + @@ -11,9 +11,9 @@ topLevel shellMaximized - - - + + + persp.actionSet:org.eclipse.mylyn.tasks.ui.navigation persp.actionSet:org.eclipse.ui.cheatsheets.actionSet @@ -84,140 +84,133 @@ persp.editorOnboardingCommand:Show Key Assist$$$Shift+Ctrl+L persp.editorOnboardingCommand:New$$$Ctrl+N persp.editorOnboardingCommand:Open Type$$$Shift+Ctrl+T - - - - + + + + org.eclipse.e4.primaryNavigationStack - active - noFocus - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:Java - + Minimized - + View categoryTag:Spring - - + + View categoryTag:Git - - - - + + + + org.eclipse.e4.secondaryNavigationStack - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Mylyn - + View categoryTag:Java - + View categoryTag:Ant - + org.eclipse.e4.secondaryDataStack Oomph Gradle Debug Version Control (Team) - + View categoryTag:General - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Terminal - + View categoryTag:Gradle - + View categoryTag:Gradle - + View categoryTag:Debug - + View categoryTag:Version Control (Team) - - View - categoryTag:Oomph - NoRestore - - + persp.actionSet:org.eclipse.mylyn.tasks.ui.navigation persp.actionSet:org.eclipse.ui.cheatsheets.actionSet @@ -266,99 +259,99 @@ persp.editorOnboardingCommand:Step Over$$$F6 persp.editorOnboardingCommand:Step Return$$$F7 persp.editorOnboardingCommand:Resume$$$F8 - - + + org.eclipse.e4.primaryNavigationStack - + View categoryTag:Debug - + View categoryTag:General - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Java - - - - + + + + org.eclipse.e4.secondaryNavigationStack - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Ant - - + + View categoryTag:General - + View categoryTag:General - + View categoryTag:Debug - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Terminal - + View categoryTag:Debug - + View categoryTag:General @@ -367,2736 +360,2719 @@ - - + + View categoryTag:Help - + View categoryTag:General - + View categoryTag:Help - + View categoryTag:Help - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:Help - - + + EditorStack - - + active + + Editor removeOnHide - org.eclipse.jdt.ui.ClassFileEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.ClassFileEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor + active + activeOnClose - + View categoryTag:Java - active - + ViewMenu menuContribution:menu - + - + View categoryTag:Java - + View categoryTag:General - + - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Mylyn - + View categoryTag:Terminal - + View categoryTag:Java - + View categoryTag:Git - + View categoryTag:Java - + View categoryTag:Spring - + ViewMenu menuContribution:menu - + - + View categoryTag:Ant - + View categoryTag:Gradle - + ViewMenu menuContribution:menu - + - + View categoryTag:Gradle - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:Version Control (Team) - + ViewMenu menuContribution:menu - + - - - - - View - categoryTag:Oomph - NoRestore - - ViewMenu - menuContribution:menu - - - - - + + toolbarSeparator - + - + Draggable - + - + toolbarSeparator - + - + Draggable - - + + - + toolbarSeparator - + - + Draggable - + Draggable - + Draggable - + Draggable - + toolbarSeparator - + - + Draggable - + - - Draggable - - - Draggable - - + toolbarSeparator - + - + toolbarSeparator - + - + Draggable - + stretch SHOW_RESTORE_MENU - + Draggable HIDEABLE SHOW_RESTORE_MENU - - + + stretch - + Draggable - + Draggable - - + + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - - + + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - - - - - - - - - - - - - - + + + + + + + + + + + + + + platform:gtk - - - - + + + + platform:gtk - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - + + + + + - - + + - - - - - - - - - + + + + + + + + + - - + + - - - + + + - - - - - + + + + + - - + + - - - + + + - - - + + + - - - - - - - - + + + + + + + + platform:gtk - - - - - + + + + + - - + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - + + + + + + + + - - + + - - - - - - + + + + + + - - - - - - + + + + + + - - + + - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Editor removeOnHide - + View categoryTag:Ant - + View categoryTag:Gradle - + View categoryTag:Gradle - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Java - + View categoryTag:Git - + View categoryTag:Git - + View categoryTag:Git - + View categoryTag:Git NoRestore - + View categoryTag:Git - + View categoryTag:Help - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Debug - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Java Browsing - + View categoryTag:Java Browsing - + View categoryTag:Java Browsing - + View categoryTag:Java Browsing - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Docker - + View categoryTag:Docker - + View categoryTag:Docker - + View categoryTag:Docker - + View categoryTag:Language Servers - + View categoryTag:Language Servers - + View categoryTag:Language Servers - + View categoryTag:Maven - + View categoryTag:Maven - + View categoryTag:Maven - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Oomph - + View categoryTag:Oomph NoRestore - + View categoryTag:Plug-in Development - + View categoryTag:General - + View categoryTag:Version Control (Team) - + View categoryTag:Version Control (Team) - + View categoryTag:Terminal - + View categoryTag:Help - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Help - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Spring - + View categoryTag:Spring - + View categoryTag:Spring - - + + glue move_after:PerspectiveSpacer SHOW_RESTORE_MENU - + move_after:Spacer Glue HIDEABLE SHOW_RESTORE_MENU - + glue move_after:SearchField SHOW_RESTORE_MENU - - - - - + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml b/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml index 46f1ff8..1212e70 100644 --- a/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml +++ b/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml @@ -1,20 +1,18 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml b/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml index 6803ddd..1b685fd 100644 --- a/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml +++ b/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml @@ -32,4 +32,6 @@ + + diff --git a/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml b/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml index 1352c02..9dcb626 100644 --- a/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml +++ b/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml @@ -65,6 +65,7 @@ +
@@ -76,4 +77,11 @@
+
+ + + + + +
diff --git a/.metadata/.plugins/org.eclipse.m2e.logback/0.log b/.metadata/.plugins/org.eclipse.m2e.logback/0.log index b6b70c4..aab21ed 100644 --- a/.metadata/.plugins/org.eclipse.m2e.logback/0.log +++ b/.metadata/.plugins/org.eclipse.m2e.logback/0.log @@ -14,3 +14,4 @@ 2026-03-26 11:31:40,355 [Worker-8: Loading available Gradle versions] INFO o.e.b.c.i.u.g.PublishedGradleVersions - Gradle version information cache is up-to-date. Trying to read. 2026-03-26 16:50:11,098 [Worker-7: Loading available Gradle versions] INFO o.e.b.c.i.u.g.PublishedGradleVersions - Gradle version information cache is up-to-date. Trying to read. 2026-03-27 07:46:24,300 [Worker-7: Loading available Gradle versions] INFO o.e.b.c.i.u.g.PublishedGradleVersions - Gradle version information cache is up-to-date. Trying to read. +2026-03-29 16:28:13,219 [Worker-2: Loading available Gradle versions] INFO o.e.b.c.i.u.g.PublishedGradleVersions - Gradle version information cache is out-of-date. Trying to update. diff --git a/.metadata/version.ini b/.metadata/version.ini index 9c361bc..8584934 100644 --- a/.metadata/version.ini +++ b/.metadata/version.ini @@ -1,3 +1,3 @@ -#Fri Mar 27 07:46:21 CET 2026 +#Sun Mar 29 16:28:09 CEST 2026 org.eclipse.core.runtime=2 org.eclipse.platform=4.39.0.v20260226-0420 diff --git a/testdaten/aufgabengruppen-export.zip b/testdaten/aufgabengruppen-export.zip index 845f9ce..ca52c80 100644 Binary files a/testdaten/aufgabengruppen-export.zip and b/testdaten/aufgabengruppen-export.zip differ diff --git a/xxxthegame/src/main/java/de/oaa/xxx/admin/AdminController.java b/xxxthegame/src/main/java/de/oaa/xxx/admin/AdminController.java index f9b08ce..4ded650 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/admin/AdminController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/admin/AdminController.java @@ -46,6 +46,7 @@ import de.oaa.xxx.subscription.UserSubscriptionEntity; import de.oaa.xxx.subscription.UserSubscriptionRepository; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/admin") @@ -54,6 +55,7 @@ public class AdminController { private final AdminRepository adminRepository; private final UserRepository userRepository; + private final UserService userService; private final MeldungRepository meldungRepository; private final FeedbackRepository feedbackRepository; private final SupportUserService supportUserService; @@ -68,6 +70,7 @@ public class AdminController { private final UserSubscriptionRepository userSubscriptionRepository; public AdminController(AdminRepository adminRepository, UserRepository userRepository, + UserService userService, MeldungRepository meldungRepository, FeedbackRepository feedbackRepository, SupportUserService supportUserService, @@ -82,6 +85,7 @@ public class AdminController { UserSubscriptionRepository userSubscriptionRepository) { this.adminRepository = adminRepository; this.userRepository = userRepository; + this.userService = userService; this.meldungRepository = meldungRepository; this.feedbackRepository = feedbackRepository; this.supportUserService = supportUserService; @@ -129,7 +133,7 @@ public class AdminController { // ── Hilfsmethoden ──────────────────────────────────────────────────────── private AdminEntity requireAdmin(Principal principal) { - var user = userRepository.findByEmail(principal.getName()).orElseThrow(); + var user = userService.requireUser(principal); return adminRepository.findByUserId(user.getUserId()) .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException( org.springframework.http.HttpStatus.FORBIDDEN, "Kein Admin")); @@ -160,8 +164,7 @@ public class AdminController { @GetMapping("/me") public ResponseEntity me(Principal principal) { - var user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) return ResponseEntity.status(403).build(); + var user = userService.requireUser(principal); return adminRepository.findByUserId(user.getUserId()) .map(a -> ResponseEntity.ok(toDto(a))) .orElse(ResponseEntity.status(403).build()); @@ -185,7 +188,7 @@ public class AdminController { @RequestBody StatusRequest body, Principal principal) { requireAdmin(principal); - var user = userRepository.findByEmail(principal.getName()).orElseThrow(); + var user = userService.requireUser(principal); MeldungEntity meldung = meldungRepository.findById(id) .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException( org.springframework.http.HttpStatus.NOT_FOUND)); @@ -357,7 +360,7 @@ public class AdminController { @DeleteMapping("/admins/{id}") public ResponseEntity deleteAdmin(@PathVariable("id") UUID id, Principal principal) { - var requestingUser = userRepository.findByEmail(principal.getName()).orElseThrow(); + var requestingUser = userService.requireUser(principal); requireSuperAdmin(principal); AdminEntity entity = adminRepository.findById(id) .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException( diff --git a/xxxthegame/src/main/java/de/oaa/xxx/config/SecurityConfig.java b/xxxthegame/src/main/java/de/oaa/xxx/config/SecurityConfig.java index 0872b8c..a897c64 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/config/SecurityConfig.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/config/SecurityConfig.java @@ -37,47 +37,48 @@ public class SecurityConfig { .requestMatchers("/error").permitAll() .requestMatchers("/api").permitAll() .requestMatchers("/userhome.html").authenticated() - .requestMatchers("/toys.html").authenticated() - .requestMatchers("/aufgaben.html").authenticated() - .requestMatchers("/entdecken.html").authenticated() - .requestMatchers("/profile.html").authenticated() - .requestMatchers("/infovanilla.html").authenticated() - .requestMatchers("/infobdsm.html").authenticated() - .requestMatchers("/infochastity.html").authenticated() - .requestMatchers("/sessionvanilla.html").authenticated() + .requestMatchers("/games/chastity/toys.html").authenticated() + .requestMatchers("/games/bdsm/aufgaben.html").authenticated() + .requestMatchers("/games/chastity/entdecken.html").authenticated() + .requestMatchers("/konto/profile.html").authenticated() + .requestMatchers("/games/vanilla/infovanilla.html").authenticated() + .requestMatchers("/games/bdsm/infobdsm.html").authenticated() + .requestMatchers("/games/chastity/infochastity.html").authenticated() + .requestMatchers("/games/vanilla/sessionvanilla.html").authenticated() .requestMatchers("/sessionbdsm.html").authenticated() - .requestMatchers("/sessionchastity.html").authenticated() - .requestMatchers("/neulock.html").authenticated() - .requestMatchers("/activelock.html").authenticated() + .requestMatchers("/games/chastity/sessionchastity.html").authenticated() + .requestMatchers("/games/chastity/neulock.html").authenticated() + .requestMatchers("/games/chastity/activelock.html").authenticated() .requestMatchers("/sessionbdsmtasks.html").authenticated() .requestMatchers("/sessionbdsmtoys.html").authenticated() .requestMatchers("/sessionbdsmingame.html").authenticated() - .requestMatchers("/neubdsm.html").authenticated() - .requestMatchers("/bdsmingame.html").authenticated() - .requestMatchers("/bdsmwarten.html").authenticated() - .requestMatchers("/personen-suchen.html").authenticated() - .requestMatchers("/freunde.html").authenticated() - .requestMatchers("/nachrichten.html").authenticated() - .requestMatchers("/benutzer.html").authenticated() - .requestMatchers("/gruppen.html").authenticated() - .requestMatchers("/gruppe.html").authenticated() - .requestMatchers("/feed.html").authenticated() - .requestMatchers("/admin.html").authenticated() - .requestMatchers("/communityvotes.html").authenticated() - .requestMatchers("/keyholder.html").authenticated() - .requestMatchers("/keyholder-finden.html").authenticated() - .requestMatchers("/meine-locks.html").authenticated() - .requestMatchers("/entdecken-vorlagen.html").authenticated() - .requestMatchers("/unlock-history.html").authenticated() - .requestMatchers("/einladungen.html").authenticated() - .requestMatchers("/joinlock.html").authenticated() - .requestMatchers("/benachrichtigungen.html").authenticated() - .requestMatchers("/abonnements.html").authenticated() + .requestMatchers("/games/bdsm/neubdsm.html").authenticated() + .requestMatchers("/games/bdsm/bdsmingame.html").authenticated() + .requestMatchers("/games/bdsm/bdsmwarten.html").authenticated() + .requestMatchers("/community/personen-suchen.html").authenticated() + .requestMatchers("/community/freunde.html").authenticated() + .requestMatchers("/community/nachrichten.html").authenticated() + .requestMatchers("/community/benutzer.html").authenticated() + .requestMatchers("/community/gruppen.html").authenticated() + .requestMatchers("/community/gruppe.html").authenticated() + .requestMatchers("/community/feed.html").authenticated() + .requestMatchers("/admin/admin.html").authenticated() + .requestMatchers("/games/chastity/communityvotes.html").authenticated() + .requestMatchers("/games/chastity/keyholder.html").authenticated() + .requestMatchers("/games/chastity/keyholder-finden.html").authenticated() + .requestMatchers("/games/chastity/meine-locks.html").authenticated() + .requestMatchers("/games/chastity/entdecken-vorlagen.html").authenticated() + .requestMatchers("/games/chastity/unlock-history.html").authenticated() + .requestMatchers("/community/einladungen.html").authenticated() + .requestMatchers("/games/chastity/joinlock.html").authenticated() + .requestMatchers("/community/benachrichtigungen.html").authenticated() + .requestMatchers("/community/abonnements.html").authenticated() .requestMatchers("/gruppen/**").authenticated() .requestMatchers("/feed/**").authenticated() .requestMatchers("/notifications/**").authenticated() .requestMatchers("/events/**").authenticated() - .requestMatchers("/*.html").permitAll() + .requestMatchers("/*.html").permitAll() + .requestMatchers("/**/*.html").permitAll() .requestMatchers("/help/*.html").permitAll() .requestMatchers("/css/**").permitAll() .requestMatchers("/js/**").permitAll() diff --git a/xxxthegame/src/main/java/de/oaa/xxx/emailchange/EmailChangeController.java b/xxxthegame/src/main/java/de/oaa/xxx/emailchange/EmailChangeController.java index cd5cbfb..6627313 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/emailchange/EmailChangeController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/emailchange/EmailChangeController.java @@ -17,12 +17,14 @@ import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.security.Principal; import java.util.UUID; +import java.util.regex.Pattern; @RestController @RequestMapping("/email-change") public class EmailChangeController { private static final Logger LOGGER = LoggerFactory.getLogger(EmailChangeController.class); + private static final Pattern EMAIL_PATTERN = Pattern.compile("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"); @Value("${app.base-url:http://localhost:8080}") private String baseUrl; @@ -52,6 +54,10 @@ public class EmailChangeController { String currentEmail = principal.getName(); String newEmail = request.newEmail(); + if (newEmail == null || newEmail.isBlank() || !EMAIL_PATTERN.matcher(newEmail).matches()) { + return ResponseEntity.badRequest().build(); + } + if (userRepository.findByEmail(newEmail).isPresent() || registrationRepository.findByEmail(newEmail).isPresent()) { return ResponseEntity.status(409).build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/feed/FeedController.java b/xxxthegame/src/main/java/de/oaa/xxx/feed/FeedController.java index 4eb54a7..6b9b339 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/feed/FeedController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/feed/FeedController.java @@ -23,7 +23,6 @@ import org.springframework.web.bind.annotation.RestController; import de.oaa.xxx.feed.dto.FeedItemDto; import de.oaa.xxx.feed.dto.FeedPostRequest; import de.oaa.xxx.feed.entity.FeedPostEntity; -import de.oaa.xxx.feed.entity.FeedPostLikeEntity; import de.oaa.xxx.feed.entity.FeedPostOptionEntity; import de.oaa.xxx.feed.entity.FeedPostVoteEntity; import de.oaa.xxx.feed.repository.FeedPostLikeRepository; @@ -40,11 +39,13 @@ import de.oaa.xxx.gruppe.repository.GruppenbeitragRepository; import de.oaa.xxx.gruppe.repository.GruppenmitgliedRepository; import de.oaa.xxx.gruppe.repository.UmfrageOptionRepository; import de.oaa.xxx.gruppe.repository.UmfrageStimmeRepository; +import de.oaa.xxx.social.LikeService; import de.oaa.xxx.social.entity.FriendshipEntity; import de.oaa.xxx.social.repository.FriendshipRepository; import de.oaa.xxx.social.repository.KommentarRepository; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,6 +69,8 @@ public class FeedController { private final GruppeRepository gruppeRepository; private final KommentarRepository kommentarRepository; private final UserRepository userRepository; + private final UserService userService; + private final LikeService likeService; public FeedController(FeedPostRepository feedPostRepository, FeedPostLikeRepository feedPostLikeRepository, @@ -81,7 +84,9 @@ public class FeedController { GruppenbeitragLikeRepository gruppenbeitragLikeRepository, GruppeRepository gruppeRepository, KommentarRepository kommentarRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService, + LikeService likeService) { this.feedPostRepository = feedPostRepository; this.feedPostLikeRepository = feedPostLikeRepository; this.feedPostOptionRepository = feedPostOptionRepository; @@ -95,6 +100,8 @@ public class FeedController { this.gruppeRepository = gruppeRepository; this.kommentarRepository = kommentarRepository; this.userRepository = userRepository; + this.userService = userService; + this.likeService = likeService; } record FeedPage(List posts, boolean hasMore) {} @@ -253,19 +260,7 @@ public class FeedController { if (myId == null) return ResponseEntity.status(401).build(); if (feedPostRepository.findById(id).isEmpty()) return ResponseEntity.notFound().build(); - var existing = feedPostLikeRepository.findByPostIdAndUserId(id, myId); - if (existing.isPresent()) { - feedPostLikeRepository.delete(existing.get()); - LOGGER.debug("User {} hat Like auf Feed-Post {} entfernt", myId, id); - } else { - FeedPostLikeEntity like = new FeedPostLikeEntity(); - like.setLikeId(UUID.randomUUID()); - like.setPostId(id); - like.setUserId(myId); - like.setLikedAt(LocalDateTime.now()); - feedPostLikeRepository.save(like); - LOGGER.debug("User {} hat Feed-Post {} geliked", myId, id); - } + likeService.toggleFeedPostLike(id, myId); return ResponseEntity.ok().build(); } @@ -337,9 +332,7 @@ public class FeedController { private UUID resolveMyId(Principal principal) { if (principal == null) return null; - return userRepository.findByEmail(principal.getName()) - .map(UserEntity::getUserId) - .orElse(null); + return userService.requireUser(principal).getUserId(); } private FeedItemDto toFeedItemDtoFromPost(FeedPostEntity p, UUID myId) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/AktiveSperre.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/AktiveSperre.java index cfd4149..f935298 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/AktiveSperre.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/AktiveSperre.java @@ -13,7 +13,7 @@ import lombok.Setter; public class AktiveSperre { private UUID aktiveSperreId; - private Mitspieler mitspieler; + private BdsmMitspieler mitspieler; private Integer minuten; private LocalDateTime startzeit; private LocalDateTime endzeit; diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameDurchfuehren.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameDurchfuehren.java index 64b0714..abf614c 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameDurchfuehren.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameDurchfuehren.java @@ -19,7 +19,7 @@ import de.oaa.xxx.games.bdsm.sperre.SperrenVerlaengernCallback; public class BdsmGameDurchfuehren { private final AufgabenList aufgabenList; - private final List mitspieler = new ArrayList<>(); + private final List mitspieler = new ArrayList<>(); private final List aktiveSperren = new ArrayList<>(); private final Integer wahrscheinlichkeitSperre; @@ -74,8 +74,8 @@ public class BdsmGameDurchfuehren { } // Echtes Fallback: nur wenn wirklich keine Kategorie eine Aufgabe liefert - Mitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV); - Mitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv); + BdsmMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV); + BdsmMitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv); String text = "Ups, da ist etwas schief gelaufen. Keine potenzielle Aufgabe gefunden. Entweder seid ihr inzwischen so gut weggesperrt, dass wirklich keine Aufgaben mehr zur Verfügung stehen, oder uns ist ein Fehler unterlaufen. {AKTIV} und {PASSIV} überbrücken die Zeit mit ein wenig Petting."; AufgabeAnzeige anzeige = new AufgabeAnzeige(); anzeige.setNameAktiverMitspieler(aktiv != null ? aktiv.getName() : ""); @@ -124,7 +124,7 @@ public class BdsmGameDurchfuehren { } } - private void setMitspielerInfo(AufgabeAnzeige anzeige, Mitspieler aktiv) { + private void setMitspielerInfo(AufgabeAnzeige anzeige, BdsmMitspieler aktiv) { if (aktiv != null) { anzeige.setMitspielerId(aktiv.getId()); anzeige.setEigenesGeraet(aktiv.isEigenesGeraet()); @@ -132,9 +132,9 @@ public class BdsmGameDurchfuehren { } private AufgabeAnzeige findUltimativeStrafe() { - Mitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV); + BdsmMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV); if (aktiv != null) { - Mitspieler passiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_PASSIV, aktiv); + BdsmMitspieler passiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_PASSIV, aktiv); if (passiv != null) { String text = "{AKTIV}, verschnüre {PASSIV} fachmännisch inkl. KG, Plugs, Knebel, Augenbinde und was dir sonst einfällt. Nutze die Ruhe für was auch immer du möchtest."; AufgabeAnzeige anzeige = new AufgabeAnzeige(); @@ -151,8 +151,8 @@ public class BdsmGameDurchfuehren { private AufgabeAnzeige findSperreVerlaengern() { if (!aktiveSperren.isEmpty()) { AktiveSperre sperre = aktiveSperren.get(new Random().nextInt(aktiveSperren.size())); - Mitspieler passiv = sperre.getMitspieler(); - Mitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV, passiv); + BdsmMitspieler passiv = sperre.getMitspieler(); + BdsmMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV, passiv); if (aktiv != null) { String text = "{AKTIV}, du entscheidest. Sollen alle bestehenden Zeitstrafen von {PASSIV} verlängert werden...?"; AufgabeAnzeige anzeige = new AufgabeAnzeige(); @@ -170,9 +170,9 @@ public class BdsmGameDurchfuehren { } private AufgabeAnzeige findeAufgabe() { - Mitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV); + BdsmMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV); if (aktiv != null) { - Mitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv); + BdsmMitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv); if (passiv != null) { List list = aufgabenList.getAufgaben().stream() .filter(aufgabe -> aufgabe.isAufgabePassend(level, aktiv, passiv)) @@ -198,9 +198,9 @@ public class BdsmGameDurchfuehren { } private AufgabeAnzeige findeStrafe() { - Mitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV); + BdsmMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV); if (aktiv != null) { - Mitspieler passiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_PASSIV, aktiv); + BdsmMitspieler passiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_PASSIV, aktiv); if (passiv != null) { List list = aufgabenList.getStrafen().stream() .filter(strafe -> strafe.isAufgabePassend(level, aktiv, passiv)) @@ -226,9 +226,9 @@ public class BdsmGameDurchfuehren { } private AufgabeAnzeige findeSperre() { - Mitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV); + BdsmMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_AKTIV); if (aktiv != null) { - Mitspieler passiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_PASSIV, aktiv); + BdsmMitspieler passiv = findeMitspielerMitRolle(RolleEnum.BESTRAFUNG_PASSIV, aktiv); if (passiv != null) { List list = aufgabenList.getSperren().stream() .filter(sperre -> sperre.isAufgabePassend(passiv)) @@ -255,16 +255,16 @@ public class BdsmGameDurchfuehren { return textMitPlatzhaltern.replace("{AKTIV}", nameAktiv).replace("{PASSIV}", namePassiv); } - private Mitspieler findeMitspielerMitRolle(RolleEnum rolle) { - List list = mitspieler.stream() + private BdsmMitspieler findeMitspielerMitRolle(RolleEnum rolle) { + List list = mitspieler.stream() .filter(m -> m.getRollen().contains(rolle)) .toList(); return list.isEmpty() ? null : list.get(new Random().nextInt(list.size())); } - private Mitspieler findeMitspielerMitRolle(RolleEnum rolle, Mitspieler gegenspieler) { + private BdsmMitspieler findeMitspielerMitRolle(RolleEnum rolle, BdsmMitspieler gegenspieler) { if (gegenspieler == null) return findeMitspielerMitRolle(rolle); - List list = mitspieler.stream() + List list = mitspieler.stream() .filter(m -> m != gegenspieler) .filter(m -> m.isPassenderSpielpartner(gegenspieler)) .filter(m -> m.getRollen().contains(rolle)) diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameService.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameService.java index 934f207..21fd5cc 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameService.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmGameService.java @@ -162,7 +162,7 @@ public class BdsmGameService { userRepository.findById(keyholderUserId).ifPresent(keyholder -> systemMessageService.send(keyholderUserId, lockeeUserId, keyholder.getName() + " hat nach dem BDSM Game ein Chastity Lock auf dich gesetzt.", - "/activelock.html", MessageCause.GAME_STATE)); + "/games/chastity/activelock.html", MessageCause.GAME_STATE)); } // Spielabschluss-Logik (History + XP + Cleanup) diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/Mitspieler.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmMitspieler.java similarity index 82% rename from xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/Mitspieler.java rename to xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmMitspieler.java index 0b07b34..c2d5166 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/Mitspieler.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/BdsmMitspieler.java @@ -3,13 +3,14 @@ package de.oaa.xxx.games.bdsm; import java.util.List; import java.util.UUID; +import de.oaa.xxx.games.common.aufgaben.CommonMitspieler; import de.oaa.xxx.games.common.aufgaben.Werkzeug; import lombok.Getter; import lombok.Setter; @Getter @Setter -public class Mitspieler { +public class BdsmMitspieler implements CommonMitspieler { private UUID id; private UUID userId; @@ -31,7 +32,7 @@ public class Mitspieler { + ", rollen=" + rollen + ", werkzeuge=" + verfuegbareWerkzeuge + "]"; } - public boolean isPassenderSpielpartner(Mitspieler other) { + public boolean isPassenderSpielpartner(BdsmMitspieler other) { if (!spieltMit.contains(other.getGeschlecht())) { return false; } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AboController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AboController.java index 39effb3..285152e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AboController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AboController.java @@ -7,7 +7,7 @@ import de.oaa.xxx.games.common.entity.GruppenAboEntity; import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository; import de.oaa.xxx.games.common.repository.GruppenAboRepository; import de.oaa.xxx.user.UserEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; @@ -37,14 +37,14 @@ public class AboController { private final GruppenAboRepository aboRepository; private final AufgabenGruppeRepository gruppeRepository; - private final UserRepository userRepository; + private final UserService userService; public AboController(GruppenAboRepository aboRepository, AufgabenGruppeRepository gruppeRepository, - UserRepository userRepository) { + UserService userService) { this.aboRepository = aboRepository; this.gruppeRepository = gruppeRepository; - this.userRepository = userRepository; + this.userService = userService; } // ── Abonnierte Gruppen laden ── @@ -54,8 +54,7 @@ public class AboController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "" + DEFAULT_PAGE_SIZE) int size, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); List dtos = aboRepository.findByUserId(user.getUserId()).stream() .map(GruppenAboEntity::getAufgabenGruppe) @@ -75,8 +74,7 @@ public class AboController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "" + DISCOVER_PAGE_SIZE) int size, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); String namePattern = name != null && !name.isBlank() ? "%" + name.trim() + "%" : null; @@ -94,8 +92,7 @@ public class AboController { @PostMapping("/{gruppenId}") public ResponseEntity subscribe(@PathVariable UUID gruppenId, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); AufgabenGruppeEntity gruppe = gruppeRepository.findById(gruppenId).orElse(null); if (gruppe == null || gruppe.isPrivateGruppe() || user.getUserId().equals(gruppe.getUserId())) { @@ -117,8 +114,7 @@ public class AboController { @DeleteMapping("/{gruppenId}") public ResponseEntity unsubscribe(@PathVariable UUID gruppenId, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); AufgabenGruppeEntity gruppe = gruppeRepository.findById(gruppenId).orElse(null); if (gruppe == null) return ResponseEntity.noContent().build(); @@ -149,7 +145,4 @@ public class AboController { return result; } - private UserEntity resolveUser(Principal principal) { - return userRepository.findByEmail(principal.getName()).orElse(null); - } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabeController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabeController.java index b39de3e..9a32775 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabeController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabeController.java @@ -9,7 +9,7 @@ import de.oaa.xxx.games.common.repository.AufgabeRepository; import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository; import de.oaa.xxx.games.common.repository.ToyRepository; import de.oaa.xxx.subscription.SubscriptionLimitService; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -39,18 +39,18 @@ public class AufgabeController { private final AufgabeRepository aufgabeRepository; private final AufgabenGruppeRepository gruppeRepository; private final ToyRepository toyRepository; - private final UserRepository userRepository; + private final UserService userService; private final SubscriptionLimitService limitService; public AufgabeController(AufgabeRepository aufgabeRepository, AufgabenGruppeRepository gruppeRepository, ToyRepository toyRepository, - UserRepository userRepository, + UserService userService, SubscriptionLimitService limitService) { this.aufgabeRepository = aufgabeRepository; this.gruppeRepository = gruppeRepository; this.toyRepository = toyRepository; - this.userRepository = userRepository; + this.userService = userService; this.limitService = limitService; } @@ -70,9 +70,7 @@ public class AufgabeController { if (gruppeEntity == null) { return ResponseEntity.badRequest().build(); } - var ownerOpt = userRepository.findByEmail(principal.getName()); - int limit = ownerOpt.map(u -> limitService.maxTasksPerGroup(u.getUserId())) - .orElse(SubscriptionLimitService.STANDARD_MAX_TASKS_PER_GROUP); + int limit = limitService.maxTasksPerGroup(userService.requireUser(principal).getUserId()); if (gruppeEntity.getAufgaben().size() >= limit) { return ResponseEntity.status(409).build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabenGruppeController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabenGruppeController.java index 0b18173..6155252 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabenGruppeController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/AufgabenGruppeController.java @@ -10,7 +10,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -36,7 +35,7 @@ import de.oaa.xxx.games.common.repository.SperreRepository; import de.oaa.xxx.games.common.repository.StrafeRepository; import de.oaa.xxx.subscription.SubscriptionLimitService; import de.oaa.xxx.user.UserEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/gruppe") @@ -51,29 +50,29 @@ public class AufgabenGruppeController { private final StrafeRepository strafeRepository; private final SperreRepository sperreRepository; private final FinisherRepository finisherRepository; - private final UserRepository userRepository; private final GruppenAboRepository aboRepository; private final AufgabenGruppeService aufgabenGruppeService; private final SubscriptionLimitService limitService; + private final UserService userService; public AufgabenGruppeController(AufgabenGruppeRepository gruppeRepository, AufgabeRepository aufgabeRepository, StrafeRepository strafeRepository, SperreRepository sperreRepository, FinisherRepository finisherRepository, - UserRepository userRepository, GruppenAboRepository aboRepository, AufgabenGruppeService aufgabenGruppeService, - SubscriptionLimitService limitService) { + SubscriptionLimitService limitService, + UserService userService) { this.gruppeRepository = gruppeRepository; this.aufgabeRepository = aufgabeRepository; this.strafeRepository = strafeRepository; this.sperreRepository = sperreRepository; this.finisherRepository = finisherRepository; - this.userRepository = userRepository; this.aboRepository = aboRepository; this.aufgabenGruppeService = aufgabenGruppeService; this.limitService = limitService; + this.userService = userService; } // ── Paginierte Listen ── @@ -102,8 +101,8 @@ public class AufgabenGruppeController { // ── Bestehende Endpunkte ── @GetMapping("/all") - public ResponseEntity getAll(@RequestParam(required = false) String search) { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + public ResponseEntity getAll(@RequestParam(required = false) String search, Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); String searchPattern = search != null ? "%" + search + "%" : null; AufgabenGruppeList list = new AufgabenGruppeList(); list.setGruppen(gruppeRepository.listWithUserAndSearch(userId, searchPattern, PageRequest.of(0, 500)) @@ -235,7 +234,8 @@ public class AufgabenGruppeController { // ── Hilfsmethoden ── private UserEntity resolveUser(Principal principal) { - return userRepository.findByEmail(principal.getName()).orElse(null); + if (principal == null) return null; + return userService.requireUser(principal); } private AufgabenGruppePage toGruppePage(Page page) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmEinladungController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmEinladungController.java index c9dad1a..339f9b9 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmEinladungController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmEinladungController.java @@ -26,6 +26,7 @@ import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.social.entity.MessageCause; import de.oaa.xxx.social.repository.FriendshipRepository; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/bdsm/einladung") @@ -36,15 +37,18 @@ public class BdsmEinladungController { private final UserRepository userRepository; private final FriendshipRepository friendshipRepository; private final SystemMessageService systemMessageService; + private final UserService userService; public BdsmEinladungController(BdsmEinladungRepository einladungRepository, UserRepository userRepository, FriendshipRepository friendshipRepository, - SystemMessageService systemMessageService) { + SystemMessageService systemMessageService, + UserService userService) { this.einladungRepository = einladungRepository; this.userRepository = userRepository; this.friendshipRepository = friendshipRepository; this.systemMessageService = systemMessageService; + this.userService = userService; } record EinladungRequest(UUID setupId, int slotIndex, UUID inviteeId) {} @@ -52,8 +56,7 @@ public class BdsmEinladungController { record SpielerDatenRequest(String spielerDatenJson) {} private UUID currentUserId(Principal principal) { - return userRepository.findByEmail(principal.getName()) - .map(u -> u.getUserId()).orElse(null); + return userService.requireUser(principal).getUserId(); } @PostMapping @@ -98,7 +101,7 @@ public class BdsmEinladungController { systemMessageService.send( inviterId, req.inviteeId(), inviterName + " hat dich zum BDSM Game eingeladen.", - "/einladungen.html", + "/community/einladungen.html", MessageCause.INVITATION ); @@ -118,7 +121,7 @@ public class BdsmEinladungController { String inviterName = userRepository.findById(userId).map(u -> u.getName()).orElse("Jemand"); systemMessageService.send(userId, e.getInviteeId(), inviterName + " hat die BDSM-Spieleinladung zurückgezogen.", - "/einladungen.html", MessageCause.INVITATION); + "/community/einladungen.html", MessageCause.INVITATION); return ResponseEntity.accepted().build(); } @@ -141,6 +144,13 @@ public class BdsmEinladungController { .orElse(ResponseEntity.noContent().build()); } + @GetMapping("/pending/count") + public ResponseEntity getPendingCount(Principal principal) { + UUID userId = currentUserId(principal); + if (userId == null) return ResponseEntity.status(401).build(); + return ResponseEntity.ok(einladungRepository.findByInviteeIdAndStatus(userId, Status.PENDING).size()); + } + @GetMapping("/pending") public ResponseEntity>> getPending(Principal principal) { UUID userId = currentUserId(principal); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmGameController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmGameController.java index a95f1eb..e32e6bc 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmGameController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmGameController.java @@ -15,7 +15,6 @@ import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -36,7 +35,7 @@ import de.oaa.xxx.games.bdsm.BdsmGame; import de.oaa.xxx.games.bdsm.BdsmGameDurchfuehren; import de.oaa.xxx.games.bdsm.BdsmGameService; import de.oaa.xxx.games.bdsm.GeschlechtEnum; -import de.oaa.xxx.games.bdsm.Mitspieler; +import de.oaa.xxx.games.bdsm.BdsmMitspieler; import de.oaa.xxx.games.common.aufgaben.AufgabenList; import de.oaa.xxx.games.common.aufgaben.Werkzeug; import de.oaa.xxx.games.bdsm.entity.AktiveSperreEntity; @@ -55,6 +54,7 @@ import de.oaa.xxx.games.chastity.cardlock.CardlockRepository; import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.social.entity.MessageCause; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/bdsm") @@ -77,12 +77,13 @@ public class BdsmGameController { private final SystemMessageService systemMessageService; private final CardlockRepository cardlockRepository; private final BdsmGameService bdsmGameService; + private final UserService userService; public BdsmGameController(BdsmGameRepository sessionRepository, MitspielerRepository mitspielerRepository, AktiveSperreRepository aktiveSperreRepository, UserRepository userRepository, BdsmEinladungRepository einladungRepository, ObjectMapper objectMapper, SystemMessageService systemMessageService, CardlockRepository cardlockRepository, - BdsmGameService bdsmGameService) { + BdsmGameService bdsmGameService, UserService userService) { this.sessionRepository = sessionRepository; this.mitspielerRepository = mitspielerRepository; this.aktiveSperreRepository = aktiveSperreRepository; @@ -92,6 +93,7 @@ public class BdsmGameController { this.systemMessageService = systemMessageService; this.cardlockRepository = cardlockRepository; this.bdsmGameService = bdsmGameService; + this.userService = userService; } @GetMapping("/{sessionId}") @@ -109,10 +111,8 @@ public class BdsmGameController { } @PostMapping - public ResponseEntity create(@RequestBody BdsmGame session) { - String email = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - UUID userId = userRepository.findByEmail(email).map(u -> u.getUserId()).orElse(null); - if (userId == null) return ResponseEntity.status(401).build(); + public ResponseEntity create(@RequestBody BdsmGame session, Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); var existingOpt = sessionRepository.findByUserId(userId); if (existingOpt.isPresent()) { BdsmGameEntity existing = existingOpt.get(); @@ -175,8 +175,7 @@ public class BdsmGameController { @DeleteMapping("/{sessionId}/verlassen") public ResponseEntity verlasseSpiel(@PathVariable UUID sessionId, Principal principal) { - UUID userId = userRepository.findByEmail(principal.getName()).map(u -> u.getUserId()).orElse(null); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); BdsmGameEntity session = sessionRepository.findById(sessionId).orElse(null); if (session == null) return ResponseEntity.notFound().build(); @@ -259,7 +258,7 @@ public class BdsmGameController { } @PostMapping("/{sessionId}/mitspieler") - public ResponseEntity addMitspieler(@RequestBody Mitspieler mitspieler, @PathVariable UUID sessionId) { + public ResponseEntity addMitspieler(@RequestBody BdsmMitspieler mitspieler, @PathVariable UUID sessionId) { if (mitspieler.getName() == null || mitspieler.getGeschlecht() == null || mitspieler.getRollen() == null || mitspieler.getRollen().isEmpty() || mitspieler.getSpieltMit() == null || mitspieler.getSpieltMit().isEmpty() || mitspieler.getVerfuegbareWerkzeuge() == null || mitspieler.getVerfuegbareWerkzeuge().isEmpty()) { @@ -345,8 +344,7 @@ public class BdsmGameController { @GetMapping("/{sessionId}/mitspieler/me") public ResponseEntity> getMeinMitspieler(@PathVariable UUID sessionId, Principal principal) { - UUID userId = userRepository.findByEmail(principal.getName()).map(u -> u.getUserId()).orElse(null); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); BdsmGameEntity session = sessionRepository.findById(sessionId).orElse(null); if (session == null) return ResponseEntity.notFound().build(); return session.getMitspieler().stream() diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmSetupDraftController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmSetupDraftController.java index bfdec92..1e8d6e8 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmSetupDraftController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/BdsmSetupDraftController.java @@ -2,7 +2,7 @@ package de.oaa.xxx.games.bdsm.controller; import de.oaa.xxx.games.bdsm.entity.BdsmSetupDraftEntity; import de.oaa.xxx.games.bdsm.repository.BdsmSetupDraftRepository; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -19,25 +19,20 @@ import java.util.UUID; public class BdsmSetupDraftController { private final BdsmSetupDraftRepository draftRepository; - private final UserRepository userRepository; + private final UserService userService; - public BdsmSetupDraftController(BdsmSetupDraftRepository draftRepository, UserRepository userRepository) { + public BdsmSetupDraftController(BdsmSetupDraftRepository draftRepository, UserService userService) { this.draftRepository = draftRepository; - this.userRepository = userRepository; + this.userService = userService; } record DraftRequest(String setupId, String settingsJson, String setupJson, String gruppenJson) {} - private UUID currentUserId(Principal principal) { - return userRepository.findByEmail(principal.getName()).map(u -> u.getUserId()).orElse(null); - } - @GetMapping public ResponseEntity> getDraft( @RequestParam(required = false) String setupId, Principal principal) { - UUID userId = currentUserId(principal); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); var lookup = (setupId != null && !setupId.isBlank()) ? draftRepository.findBySetupId(setupId) : draftRepository.findByUserId(userId); @@ -55,8 +50,7 @@ public class BdsmSetupDraftController { @PutMapping public ResponseEntity saveDraft(@RequestBody DraftRequest req, Principal principal) { - UUID userId = currentUserId(principal); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); BdsmSetupDraftEntity d = draftRepository.findByUserId(userId) .orElseGet(() -> { BdsmSetupDraftEntity n = new BdsmSetupDraftEntity(); n.setUserId(userId); return n; }); if (req.setupId() != null) d.setSetupId(req.setupId()); @@ -70,8 +64,7 @@ public class BdsmSetupDraftController { @DeleteMapping public ResponseEntity deleteDraft(Principal principal) { - UUID userId = currentUserId(principal); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); draftRepository.findByUserId(userId).ifPresent(draftRepository::delete); return ResponseEntity.accepted().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/FavoritController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/FavoritController.java index 3d4d80b..e8ae9e4 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/FavoritController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/FavoritController.java @@ -4,11 +4,11 @@ import de.oaa.xxx.games.common.aufgaben.Favorit; import de.oaa.xxx.games.common.aufgaben.FavoritList; import de.oaa.xxx.games.common.entity.FavoritEntity; import de.oaa.xxx.games.common.repository.FavoritRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import java.security.Principal; import java.util.List; import java.util.UUID; @@ -30,9 +31,11 @@ public class FavoritController { private static final Logger LOGGER = LoggerFactory.getLogger(FavoritController.class); private final FavoritRepository favoritRepository; + private final UserService userService; - public FavoritController(FavoritRepository favoritRepository) { + public FavoritController(FavoritRepository favoritRepository, UserService userService) { this.favoritRepository = favoritRepository; + this.userService = userService; } @GetMapping("/{favoritId}") @@ -43,8 +46,8 @@ public class FavoritController { } @GetMapping - public ResponseEntity all() { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + public ResponseEntity all(Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); List entities = favoritRepository.findByUserId(userId); FavoritList result = new FavoritList(); result.setFavoriten(entities.stream().map(FavoritEntity::toFavorit).toList()); @@ -52,8 +55,8 @@ public class FavoritController { } @PostMapping - public ResponseEntity create(@RequestBody Favorit favorit) { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + public ResponseEntity create(@RequestBody Favorit favorit, Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); if (favorit.getAufgabenGruppeId() == null) { return ResponseEntity.badRequest().build(); } @@ -72,9 +75,9 @@ public class FavoritController { } @DeleteMapping - public ResponseEntity delete(@RequestBody Favorit favorit) { + public ResponseEntity delete(@RequestBody Favorit favorit, Principal principal) { try { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + UUID userId = userService.requireUser(principal).getUserId(); favoritRepository.findByUserIdAndAufgabenGruppeId(userId, favorit.getAufgabenGruppeId()) .forEach(favoritRepository::delete); return ResponseEntity.accepted().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/ToyController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/ToyController.java index 237b98c..b7978be 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/ToyController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/controller/ToyController.java @@ -8,7 +8,7 @@ import de.oaa.xxx.games.common.repository.GruppenAboRepository; import de.oaa.xxx.games.common.repository.ToyRepository; import de.oaa.xxx.subscription.SubscriptionLimitService; import de.oaa.xxx.user.UserEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -45,16 +45,16 @@ public class ToyController { private static final int DEFAULT_PAGE_SIZE = 12; private final ToyRepository toyRepository; - private final UserRepository userRepository; + private final UserService userService; private final GruppenAboRepository aboRepository; private final SubscriptionLimitService limitService; public ToyController(ToyRepository toyRepository, - UserRepository userRepository, + UserService userService, GruppenAboRepository aboRepository, SubscriptionLimitService limitService) { this.toyRepository = toyRepository; - this.userRepository = userRepository; + this.userService = userService; this.aboRepository = aboRepository; this.limitService = limitService; } @@ -64,10 +64,7 @@ public class ToyController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "" + DEFAULT_PAGE_SIZE) int size, Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); Page result = toyRepository.findByUserId( user.getUserId(), PageRequest.of(page, size, Sort.by("name"))); return ResponseEntity.ok(toToyPage(result)); @@ -88,8 +85,7 @@ public class ToyController { */ @GetMapping("/available") public ResponseEntity> available(Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); List own = toyRepository.findByUserId(user.getUserId(), PageRequest.of(0, 500, Sort.by("name"))).getContent(); List system = toyRepository.findByUserIdIsNull(PageRequest.of(0, 500, Sort.by("name"))).getContent(); @@ -136,10 +132,7 @@ public class ToyController { if (toy.getName() == null || toy.getName().isBlank()) { return ResponseEntity.badRequest().build(); } - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); if (toyRepository.existsByNameIgnoreCaseAndUserIdIsNull(toy.getName()) || toyRepository.existsByNameIgnoreCaseAndUserId(toy.getName(), user.getUserId())) { return ResponseEntity.status(409) @@ -162,10 +155,7 @@ public class ToyController { @PostMapping("/copy/{toyId}") public ResponseEntity copy(@PathVariable UUID toyId, Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); ToyEntity source = toyRepository.findById(toyId).orElse(null); if (source == null) { return ResponseEntity.notFound().build(); @@ -194,10 +184,7 @@ public class ToyController { if (toy.getName() == null || toy.getName().isBlank()) { return ResponseEntity.badRequest().build(); } - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); ToyEntity entity = toyRepository.findById(toyId).orElse(null); if (entity == null) { return ResponseEntity.notFound().build(); @@ -223,10 +210,7 @@ public class ToyController { @DeleteMapping("/{toyId}") public ResponseEntity delete(@PathVariable UUID toyId, Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); ToyEntity toy = toyRepository.findById(toyId).orElse(null); if (toy == null) { return ResponseEntity.noContent().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/AktiveSperreEntity.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/AktiveSperreEntity.java index 3d51149..d5150c5 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/AktiveSperreEntity.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/AktiveSperreEntity.java @@ -7,7 +7,7 @@ import java.util.Optional; import java.util.UUID; import de.oaa.xxx.games.bdsm.AktiveSperre; -import de.oaa.xxx.games.bdsm.Mitspieler; +import de.oaa.xxx.games.bdsm.BdsmMitspieler; import de.oaa.xxx.games.common.aufgaben.Werkzeug; import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; @@ -52,7 +52,7 @@ public class AktiveSperreEntity { @JoinColumn(name = "sessionId", nullable = false) private BdsmGameEntity session; - public AktiveSperre toSperre(List mitspielerList) { + public AktiveSperre toSperre(List mitspielerList) { AktiveSperre sperre = new AktiveSperre(); sperre.setAktiveSperreId(aktiveSperreId); sperre.setEndzeit(endzeit); @@ -70,8 +70,8 @@ public class AktiveSperreEntity { + ", " + minuten + "min, von=" + startzeit + ", bis=" + endzeit + ", fuer=" + fuer + "]"; } - private Mitspieler getMitspielerFromList(List mitspielerList, UUID id) { - Optional first = mitspielerList.stream().filter(m -> m.getId().equals(id)).findFirst(); + private BdsmMitspieler getMitspielerFromList(List mitspielerList, UUID id) { + Optional first = mitspielerList.stream().filter(m -> m.getId().equals(id)).findFirst(); return first.orElse(null); } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/MitspielerEntity.java b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/MitspielerEntity.java index 59ed9f3..bb0b2cc 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/MitspielerEntity.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/bdsm/entity/MitspielerEntity.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.UUID; import de.oaa.xxx.games.bdsm.GeschlechtEnum; -import de.oaa.xxx.games.bdsm.Mitspieler; +import de.oaa.xxx.games.bdsm.BdsmMitspieler; import de.oaa.xxx.games.bdsm.RolleEnum; import de.oaa.xxx.games.common.aufgaben.Werkzeug; import jakarta.persistence.CollectionTable; @@ -70,8 +70,8 @@ public class MitspielerEntity { + ", geschlecht=" + geschlecht + ", rollen=" + rollen + ", werkzeuge=" + werkzeuge + "]"; } - public Mitspieler toMitspieler() { - Mitspieler mitspieler = new Mitspieler(); + public BdsmMitspieler toMitspieler() { + BdsmMitspieler mitspieler = new BdsmMitspieler(); mitspieler.setGeschlecht(geschlecht); mitspieler.setId(mitspielerId); mitspieler.setUserId(userId); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardLockController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardLockController.java index 110ea10..3c20039 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardLockController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardLockController.java @@ -60,6 +60,7 @@ import de.oaa.xxx.games.chastity.unlock.UnlockCodeHistoryService; import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.subscription.SubscriptionLimitService; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/keyholder") @@ -80,6 +81,7 @@ public class CardLockController { private final SystemMessageService systemMessageService; private final CardLockServiceFactory cardLockServiceFactory; private final SubscriptionLimitService subscriptionLimitService; + private final UserService userService; @Value("${app.base-url:http://localhost:8080}") private String baseUrl; @@ -99,7 +101,8 @@ public class CardLockController { SystemMessageService systemMessageService, CardLockServiceFactory cardLockServiceFactory, LockControlFactory lockControlFactory, - SubscriptionLimitService subscriptionLimitService) { + SubscriptionLimitService subscriptionLimitService, + UserService userService) { this.cardlockRepository = cardlockRepository; this.userRepository = userRepository; this.invitationRepository = invitationRepository; @@ -115,6 +118,7 @@ public class CardLockController { this.systemMessageService = systemMessageService; this.cardLockServiceFactory = cardLockServiceFactory; this.subscriptionLimitService = subscriptionLimitService; + this.userService = userService; } record CreateCardLockRequest(String name, UUID keyholder, UUID lockeeUserId, boolean lockeeDetailsVisible, @@ -138,10 +142,7 @@ public class CardLockController { public ResponseEntity> createCardLock(@RequestBody CreateCardLockRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); if (req.initialCards() == null || req.initialCards().isEmpty() || req.pickEveryMinute() == null @@ -191,7 +192,7 @@ public class CardLockController { String lockName = req.name() != null && !req.name().isBlank() ? req.name() : "Unbenanntes Lock"; sendMessage(myId, lockee.getUserId(), me.getName() + " hat dich als Lockee für das Lock „" + lockName + "\" eingeladen.", - "/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); + "/community/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); return ResponseEntity.ok(Map.of("lockId", lock.getLockId().toString(), "lockeeInvitationSent", true)); } @@ -263,7 +264,7 @@ public class CardLockController { String lockName = req.name() != null && !req.name().isBlank() ? req.name() : "Unbenanntes Lock"; sendMessage(me.getUserId(), kh.getUserId(), me.getName() + " hat dich als Keyholder*In für das Lock „" + lockName + "\" eingeladen.", - "/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); + "/community/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); keyholderPending = true; } @@ -276,10 +277,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/draw") @Transactional public ResponseEntity> drawCard(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -305,9 +303,10 @@ public class CardLockController { if (dto.unlockCode() != null && !dto.unlockCode().isBlank()) { unlockCodeHistoryService.save(myId, l.getLockId(), l.getName(), dto.unlockCode(), "GREEN_CARD"); if (l.getKeyholder() != null) { + String meName = userRepository.findById(myId).map(u -> u.getName()).orElse(""); sendMessage(myId, l.getKeyholder(), - meOpt.get().getName() + " hat die grüne Karte gezogen! Der Entsperrcode wurde angezeigt.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + meName + " hat die grüne Karte gezogen! Der Entsperrcode wurde angezeigt.", + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); } } @@ -317,10 +316,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/hygiene/start") @Transactional public ResponseEntity> startHygieneOpening(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -337,10 +333,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/hygiene/end") @Transactional public ResponseEntity> endHygieneOpening(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -356,10 +349,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/task/complete") @Transactional public ResponseEntity completeTask(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -376,9 +366,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/relock") @Transactional public ResponseEntity relock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -394,10 +382,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/green/keep") @Transactional public ResponseEntity greenKeep(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -411,8 +396,9 @@ public class CardLockController { // Grüne Karte zurückgelegt → Keyholder benachrichtigen if (l.getKeyholder() != null) { + String meName = userRepository.findById(myId).map(u -> u.getName()).orElse(""); sendMessage(myId, l.getKeyholder(), - meOpt.get().getName() + " hat die grüne Karte zurückgelegt und bleibt im Lock.", "/keyholder.html", + meName + " hat die grüne Karte zurückgelegt und bleibt im Lock.", "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); } @@ -421,10 +407,7 @@ public class CardLockController { @GetMapping("/mylock") public ResponseEntity> getMyActiveLock(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var activeLockId = cardLockServiceFactory.findActiveLockId(myId); if (activeLockId.isEmpty()) return ResponseEntity.noContent().build(); @@ -433,10 +416,7 @@ public class CardLockController { @GetMapping("/cardlock/{lockId}") public ResponseEntity> getLock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -547,7 +527,7 @@ public class CardLockController { assignedTaskRepository.save(t); sendMessage(l.getKeyholder(), l.getLockee(), "Die dir gestellte Aufgabe ist abgelaufen, ohne dass du reagiert hast. Die Strafe wurde automatisch angewendet.", - "/activelock.html?lockId=" + l.getLockId(), de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activelock.html?lockId=" + l.getLockId(), de.oaa.xxx.social.entity.MessageCause.GAME_STATE); } } @@ -614,10 +594,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/verification/start") @Transactional public ResponseEntity> startVerification(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -660,10 +637,7 @@ public class CardLockController { @Transactional public ResponseEntity completeVerification(@PathVariable UUID lockId, @PathVariable UUID verificationId, @RequestParam MultipartFile image, Principal principal) throws IOException { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -683,9 +657,9 @@ public class CardLockController { var lock = lockOpt.get(); if (lock.getKeyholder() != null) { - var lockee = meOpt.get(); - sendMessage(myId, lock.getKeyholder(), "📸 " + lockee.getName() + " hat eine Verifikation eingereicht.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + String meName = userRepository.findById(myId).map(u -> u.getName()).orElse(""); + sendMessage(myId, lock.getKeyholder(), "📸 " + meName + " hat eine Verifikation eingereicht.", + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); } return ResponseEntity.noContent().build(); @@ -716,10 +690,7 @@ public class CardLockController { @DeleteMapping("/cardlock/{lockId}/verification/today") @Transactional public ResponseEntity renewVerification(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -740,12 +711,22 @@ public class CardLockController { // ── Keyholder-Dashboard Endpunkte ── + @GetMapping("/invitations/mine/count") + public ResponseEntity countMyInvitations(Principal principal) { + UUID myId = userService.requireUser(principal).getUserId(); + int count = 0; + for (var inv : invitationRepository.findByKeyholderUserId(myId)) { + var lockOpt = cardlockRepository.findById(inv.getLockId()); + if (lockOpt.isEmpty()) continue; + if (lockOpt.get().getKeyholder() != null) continue; + count++; + } + return ResponseEntity.ok(count); + } + @GetMapping("/invitations/mine") public ResponseEntity>> getMyInvitations(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var invitations = invitationRepository.findByKeyholderUserId(myId); List> result = new ArrayList<>(); @@ -776,10 +757,7 @@ public class CardLockController { @Transactional @DeleteMapping("/invitations/mine/{token}") public ResponseEntity declineInvitation(@PathVariable String token, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var invOpt = invitationRepository.findByToken(token); @@ -805,10 +783,7 @@ public class CardLockController { @GetMapping("/invitations/sent") public ResponseEntity>> getSentKeyholderInvitations(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var invitations = invitationRepository.findByLockeeUserId(myId); List> result = new ArrayList<>(); @@ -838,10 +813,7 @@ public class CardLockController { @Transactional @DeleteMapping("/invitations/sent/{token}") public ResponseEntity cancelSentKeyholderInvitation(@PathVariable String token, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var invOpt = invitationRepository.findByToken(token); @@ -868,10 +840,7 @@ public class CardLockController { @GetMapping("/as-keyholder") public ResponseEntity>> getLocksAsKeyholder(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var locks = cardlockRepository.findByKeyholderAndUnlockTimeIsNull(myId); List> result = new ArrayList<>(); @@ -898,10 +867,7 @@ public class CardLockController { @GetMapping("/as-keyholder/{lockId}") public ResponseEntity> getLockAsKeyholder(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1058,10 +1024,7 @@ public class CardLockController { @Transactional @DeleteMapping("/cardlock/{lockId}") public ResponseEntity deleteLock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1090,10 +1053,7 @@ public class CardLockController { @Transactional public ResponseEntity addCards(@PathVariable UUID lockId, @RequestBody ModifyCardsRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = cardlockRepository.findById(lockId); @@ -1130,7 +1090,7 @@ public class CardLockController { ? me.getName() + " hat " + toAdd.size() + " Karte(n) zu deinem Lock hinzugefügt: " + detail + "." : me.getName() + " hat Karten zu deinem Lock hinzugefügt."; - sendMessage(myId, l.getLockee(), msgText, "/activelock.html?lockId=" + lockId, + sendMessage(myId, l.getLockee(), msgText, "/games/chastity/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); @@ -1140,10 +1100,7 @@ public class CardLockController { @Transactional public ResponseEntity> removeCards(@PathVariable UUID lockId, @RequestBody ModifyCardsRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = cardlockRepository.findById(lockId); @@ -1195,7 +1152,7 @@ public class CardLockController { ? me.getName() + " hat " + removed.size() + " Karte(n) aus deinem Lock entfernt: " + detail + "." : me.getName() + " hat Karten aus deinem Lock entfernt."; - sendMessage(myId, l.getLockee(), msgText, "/activelock.html?lockId=" + lockId, + sendMessage(myId, l.getLockee(), msgText, "/games/chastity/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); @@ -1210,10 +1167,7 @@ public class CardLockController { @GetMapping("/cardlock/unlock-history") public ResponseEntity>> getUnlockHistory(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var entries = unlockCodeHistoryRepository.findByUserIdOrderByReceivedAtDesc(myId, org.springframework.data.domain.PageRequest.of(0, 10)); List> result = new ArrayList<>(); @@ -1238,10 +1192,7 @@ public class CardLockController { @PostMapping("/as-keyholder/{lockId}/assign-task") public ResponseEntity assignTask(@PathVariable UUID lockId, @RequestBody AssignTaskRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1282,7 +1233,7 @@ public class CardLockController { sendMessage(me.getUserId(), l.getLockee(), me.getName() + " hat dir eine Aufgabe gestellt. Du hast " + req.acceptDeadlineMinutes() + " Minuten, um sie anzunehmen.", - "/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -1293,10 +1244,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/assigned-tasks/{taskId}/accept") public ResponseEntity acceptAssignedTask(@PathVariable UUID lockId, @PathVariable UUID taskId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1343,8 +1291,9 @@ public class CardLockController { assignedTaskRepository.save(task); cardlockRepository.save(l); - sendMessage(myId, l.getKeyholder(), meOpt.get().getName() + " hat die gestellte Aufgabe angenommen.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + String meName = userRepository.findById(myId).map(u -> u.getName()).orElse(""); + sendMessage(myId, l.getKeyholder(), meName + " hat die gestellte Aufgabe angenommen.", + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -1354,10 +1303,7 @@ public class CardLockController { @PostMapping("/cardlock/{lockId}/assigned-tasks/{taskId}/decline") public ResponseEntity declineAssignedTask(@PathVariable UUID lockId, @PathVariable UUID taskId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1377,9 +1323,10 @@ public class CardLockController { cardLockServiceFactory.create(l).applyAssignedTaskPenalty(task); assignedTaskRepository.save(task); + String meNameDecl = userRepository.findById(myId).map(u -> u.getName()).orElse(""); sendMessage(myId, l.getKeyholder(), - meOpt.get().getName() + " hat die gestellte Aufgabe abgelehnt. Die Strafe wurde angewendet.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + meNameDecl + " hat die gestellte Aufgabe abgelehnt. Die Strafe wurde angewendet.", + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -1389,10 +1336,7 @@ public class CardLockController { @DeleteMapping("/as-keyholder/{lockId}/assigned-tasks/{taskId}") public ResponseEntity cancelAssignedTask(@PathVariable UUID lockId, @PathVariable UUID taskId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1419,10 +1363,7 @@ public class CardLockController { @PostMapping("/as-keyholder/{lockId}/freeze") public ResponseEntity freezeLock(@PathVariable UUID lockId, @RequestBody FreezeRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = cardlockRepository.findById(lockId); @@ -1454,7 +1395,7 @@ public class CardLockController { + until.toLocalDate().format(java.time.format.DateTimeFormatter.ofPattern("dd.MM.yyyy")) + " " + until.toLocalTime().format(java.time.format.DateTimeFormatter.ofPattern("HH:mm")) + " Uhr eingefroren.", - "/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -1462,10 +1403,7 @@ public class CardLockController { @Transactional @DeleteMapping("/as-keyholder/{lockId}/freeze") public ResponseEntity unfreezeLock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = cardlockRepository.findById(lockId); @@ -1483,7 +1421,7 @@ public class CardLockController { cardlockRepository.save(l); sendMessage(myId, l.getLockee(), me.getName() + " hat dein Lock wieder entfroren.", - "/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -1491,10 +1429,7 @@ public class CardLockController { @Transactional @PostMapping("/as-keyholder/{lockId}/request-unlock") public ResponseEntity requestUnlock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = cardlockRepository.findById(lockId); if (lockOpt.isEmpty()) @@ -1508,7 +1443,7 @@ public class CardLockController { sendMessage(myId, l.getLockee(), "Dein Keyholder hat das Lock freigeschaltet. Du erhältst beim nächsten Laden deinen Entsperrcode.", - "/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -1516,10 +1451,7 @@ public class CardLockController { @Transactional @PostMapping("/cardlock/{lockId}/emergency-unlock") public ResponseEntity requestEmergencyUnlock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = cardlockRepository.findById(lockId); @@ -1543,7 +1475,7 @@ public class CardLockController { // Keyholderin benachrichtigen sendMessage(myId, l.getKeyholder(), "⚠️ NOTFALL: " + me.getName() + " bittet dringend um Freigabe des Locks. Bitte reagiere innerhalb einer Stunde, sonst öffnet sich das Lock automatisch.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.EMERGENCY); + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.EMERGENCY); } cardlockRepository.save(l); return ResponseEntity.noContent().build(); @@ -1568,19 +1500,19 @@ public class CardLockController { throws Exception { var invOpt = invitationRepository.findByToken(token); if (invOpt.isEmpty()) { - response.sendRedirect("/keyholder-invitation-confirmed.html?status=invalid"); + response.sendRedirect("/games/chastity/keyholder-invitation-confirmed.html?status=invalid"); return; } var inv = invOpt.get(); var lockOpt = cardlockRepository.findById(inv.getLockId()); if (lockOpt.isEmpty()) { - response.sendRedirect("/keyholder-invitation-confirmed.html?status=invalid"); + response.sendRedirect("/games/chastity/keyholder-invitation-confirmed.html?status=invalid"); return; } var lock = lockOpt.get(); lock.setKeyholder(inv.getKeyholderUserId()); cardlockRepository.save(lock); invitationRepository.delete(inv); - response.sendRedirect("/keyholder.html"); + response.sendRedirect("/games/chastity/keyholder.html"); } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardlockTemplateController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardlockTemplateController.java index 1b534d0..e4677d9 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardlockTemplateController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/cardlock/CardlockTemplateController.java @@ -3,7 +3,7 @@ package de.oaa.xxx.games.chastity.cardlock; import de.oaa.xxx.games.chastity.tasks.Task; import de.oaa.xxx.games.chastity.tasks.TaskMode; import de.oaa.xxx.subscription.SubscriptionLimitService; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -18,16 +18,16 @@ import java.util.stream.Collectors; public class CardlockTemplateController { private final CardlockTemplateRepository templateRepository; - private final UserRepository userRepository; + private final UserService userService; private final TimeLockTemplateRepository timeLockTemplateRepository; private final SubscriptionLimitService limitService; public CardlockTemplateController(CardlockTemplateRepository templateRepository, - UserRepository userRepository, + UserService userService, TimeLockTemplateRepository timeLockTemplateRepository, SubscriptionLimitService limitService) { this.templateRepository = templateRepository; - this.userRepository = userRepository; + this.userService = userService; this.timeLockTemplateRepository = timeLockTemplateRepository; this.limitService = limitService; } @@ -65,9 +65,7 @@ public class CardlockTemplateController { @GetMapping public ResponseEntity>> list(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List> result = templateRepository.findByOwner(myId) .stream().map(this::toDto).collect(Collectors.toList()); return ResponseEntity.ok(result); @@ -75,9 +73,7 @@ public class CardlockTemplateController { @PostMapping public ResponseEntity> create(@RequestBody TemplateRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (req.pickEveryMinute() == null || req.pickEveryMinute() < 1) return ResponseEntity.badRequest().build(); @@ -100,9 +96,7 @@ public class CardlockTemplateController { public ResponseEntity> update(@PathVariable UUID id, @RequestBody TemplateRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var opt = templateRepository.findById(id); if (opt.isEmpty()) return ResponseEntity.notFound().build(); @@ -121,9 +115,7 @@ public class CardlockTemplateController { @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var opt = templateRepository.findById(id); if (opt.isEmpty()) return ResponseEntity.notFound().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockService.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockService.java index 476c011..868ab2f 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockService.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockService.java @@ -132,7 +132,7 @@ public abstract class BaseLockService { userRepository.findById(lock.getKeyholder()).ifPresent(kh -> sendMessage(lock.getLockee(), kh.getUserId(), "Deine Lockee hat die Hygiene-Öffnung um " + overtime + " Minuten überschritten.", - "/keyholder.html?lockId=" + lock.getLockId(), + "/games/chastity/keyholder.html?lockId=" + lock.getLockId(), de.oaa.xxx.social.entity.MessageCause.GAME_STATE)); } @@ -181,7 +181,7 @@ public abstract class BaseLockService { userRepository.findById(lock.getKeyholder()) .ifPresent(kh -> sendMessage(lock.getLockee(), kh.getUserId(), "Deine Lockee hat eine Aufgaben-Karte gezogen – wähle eine Aufgabe aus.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE)); + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE)); } protected void startCommunityVote() { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockTemplateController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockTemplateController.java index db5d63a..295ae9a 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockTemplateController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockTemplateController.java @@ -2,7 +2,7 @@ package de.oaa.xxx.games.chastity.common; import de.oaa.xxx.games.chastity.cardlock.CardlockTemplateEntity; import de.oaa.xxx.games.chastity.timelock.TimeLockTemplateEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.http.ResponseEntity; @@ -16,12 +16,12 @@ import java.util.*; public class BaseLockTemplateController { private final BaseLockTemplateRepository templateRepository; - private final UserRepository userRepository; + private final UserService userService; public BaseLockTemplateController(BaseLockTemplateRepository templateRepository, - UserRepository userRepository) { + UserService userService) { this.templateRepository = templateRepository; - this.userRepository = userRepository; + this.userService = userService; } @GetMapping @@ -29,9 +29,7 @@ public class BaseLockTemplateController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var pageable = PageRequest.of(page, Math.min(size, 50), Sort.by("name")); var pageResult = templateRepository.findByOwner(myId, pageable); @@ -60,9 +58,7 @@ public class BaseLockTemplateController { @GetMapping("/{id}") public ResponseEntity> getById(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var opt = templateRepository.findById(id); if (opt.isEmpty()) return ResponseEntity.notFound().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/TemplateExploreController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/TemplateExploreController.java index 11ed445..47a7fdd 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/TemplateExploreController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/TemplateExploreController.java @@ -6,6 +6,7 @@ import de.oaa.xxx.games.chastity.timelock.TimeLockTemplateEntity; import de.oaa.xxx.games.chastity.timelock.TimeLockTemplateRepository; import de.oaa.xxx.games.chastity.tasks.TaskMode; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @@ -27,17 +28,20 @@ public class TemplateExploreController { private final TimeLockTemplateRepository timeLockTemplateRepository; private final CardlockTemplateRepository cardlockTemplateRepository; private final UserRepository userRepository; + private final UserService userService; public TemplateExploreController(BaseLockTemplateRepository templateRepository, TemplateSubscriptionRepository subscriptionRepository, TimeLockTemplateRepository timeLockTemplateRepository, CardlockTemplateRepository cardlockTemplateRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService) { this.templateRepository = templateRepository; this.subscriptionRepository = subscriptionRepository; this.timeLockTemplateRepository = timeLockTemplateRepository; this.cardlockTemplateRepository = cardlockTemplateRepository; this.userRepository = userRepository; + this.userService = userService; } // ── Öffentliche Vorlagen entdecken ──────────────────────────────────────── @@ -49,9 +53,7 @@ public class TemplateExploreController { @RequestParam(defaultValue = "") String q, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); size = Math.min(size, 20); var pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "subscriberCount")); @@ -79,9 +81,7 @@ public class TemplateExploreController { @GetMapping("/{id}/public") public ResponseEntity> getTemplate( @PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var tOpt = templateRepository.findById(id); if (tOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -99,9 +99,7 @@ public class TemplateExploreController { @GetMapping("/mine") public ResponseEntity>> getMyTemplates(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List> result = templateRepository.findByOwner(myId).stream() .map(t -> toPublicDto(t, myId, Set.of())) @@ -113,9 +111,7 @@ public class TemplateExploreController { @GetMapping("/subscribed") public ResponseEntity>> getSubscribedTemplates(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List subs = subscriptionRepository.findByUserId(myId); Set subscribedIds = subs.stream().map(TemplateSubscriptionEntity::getTemplateId).collect(Collectors.toSet()); @@ -136,9 +132,7 @@ public class TemplateExploreController { @PostMapping("/{id}/subscribe") @Transactional public ResponseEntity subscribe(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var tOpt = templateRepository.findById(id); if (tOpt.isEmpty() || !tOpt.get().isPublished()) return ResponseEntity.notFound().build(); @@ -164,9 +158,7 @@ public class TemplateExploreController { @DeleteMapping("/{id}/subscribe") @Transactional public ResponseEntity unsubscribe(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var subOpt = subscriptionRepository.findByUserIdAndTemplateId(myId, id); if (subOpt.isEmpty()) return ResponseEntity.noContent().build(); @@ -186,9 +178,7 @@ public class TemplateExploreController { @PostMapping("/{id}/fork") @Transactional public ResponseEntity> fork(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var tOpt = templateRepository.findById(id); if (tOpt.isEmpty() || !tOpt.get().isPublished()) return ResponseEntity.notFound().build(); @@ -244,9 +234,7 @@ public class TemplateExploreController { @PatchMapping("/{id}/publish") @Transactional public ResponseEntity publish(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); var tOpt = templateRepository.findById(id); if (tOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -264,9 +252,7 @@ public class TemplateExploreController { @DeleteMapping("/{id}/publish") @Transactional public ResponseEntity unpublish(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var tOpt = templateRepository.findById(id); if (tOpt.isEmpty()) return ResponseEntity.notFound().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteController.java index c6cff10..52237fd 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteController.java @@ -14,22 +14,22 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import de.oaa.xxx.games.chastity.common.BaseLockRepository; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/games/chastity/community/taskvote") public class CommunityTaskVoteController { - private final UserRepository userRepository; + private final UserService userService; private final CommunityTaskVoteRepository taskVoteRepository; private final CommunityTaskVoteEntryRepository taskVoteEntryRepository; private final BaseLockRepository baseLockRepository; - public CommunityTaskVoteController(UserRepository userRepository, + public CommunityTaskVoteController(UserService userService, CommunityTaskVoteRepository taskVoteRepository, CommunityTaskVoteEntryRepository taskVoteEntryRepository, BaseLockRepository baseLockRepository) { - this.userRepository = userRepository; + this.userService = userService; this.taskVoteRepository = taskVoteRepository; this.taskVoteEntryRepository = taskVoteEntryRepository; this.baseLockRepository = baseLockRepository; @@ -37,10 +37,7 @@ public class CommunityTaskVoteController { @GetMapping("/{displayId}") public ResponseEntity getVote(@PathVariable UUID displayId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var voteOpt = taskVoteRepository.findById(displayId); if (voteOpt.isEmpty() || !voteOpt.get().isActive()) { @@ -74,10 +71,7 @@ public class CommunityTaskVoteController { @Transactional public ResponseEntity castVote(@PathVariable UUID displayId, @PathVariable int taskIndex, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) - return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var voteOpt = taskVoteRepository.findById(displayId); if (voteOpt.isEmpty()) diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteScheduler.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteScheduler.java index d43ada6..28e317e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteScheduler.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityTaskVoteScheduler.java @@ -104,7 +104,7 @@ public class CommunityTaskVoteScheduler { sendMessage(lock.getLockee(), "Die Community hat für deine Aufgabe abgestimmt: \"" + task.getTitle() + "\"", - "/activelock.html?lockId=" + lock.getLockId()); + "/games/chastity/activelock.html?lockId=" + lock.getLockId()); } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityVerificationController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityVerificationController.java index 5d9dae6..b3c221d 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityVerificationController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/community/CommunityVerificationController.java @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController; import de.oaa.xxx.games.chastity.common.CodeCreator; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/games/chastity/community/verification") @@ -26,12 +27,16 @@ public class CommunityVerificationController { private final CommunityVerificationRepository verificationRepository; private final CommunityVerificationVoteRepository verificationVoteRepository; private final UserRepository userRepository; + private final UserService userService; public CommunityVerificationController(CommunityVerificationRepository verificationRepository, - CommunityVerificationVoteRepository verificationVoteRepository, UserRepository userRepository) { + CommunityVerificationVoteRepository verificationVoteRepository, + UserRepository userRepository, + UserService userService) { this.verificationRepository = verificationRepository; this.verificationVoteRepository = verificationVoteRepository; this.userRepository = userRepository; + this.userService = userService; } @GetMapping("/{displayId}") @@ -78,10 +83,7 @@ public class CommunityVerificationController { @PutMapping("/{displayId}") public ResponseEntity update(@PathVariable UUID displayId, @RequestBody CommunityVerificationDTO dto, Principal principal) { - var user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + userService.requireUser(principal); var entity = verificationRepository.findById(displayId).orElse(null); if (entity == null) { return ResponseEntity.notFound().build(); @@ -99,8 +101,7 @@ public class CommunityVerificationController { @PostMapping("/{verificationId}/vote/") public ResponseEntity addVote(@PathVariable UUID verificationId, @RequestBody CommunityVerificationVoteDTO dto, Principal principal) { - var user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) return ResponseEntity.status(401).build(); + var user = userService.requireUser(principal); if (!verificationRepository.existsById(verificationId)) return ResponseEntity.notFound().build(); var vEntity = verificationRepository.findById(verificationId).orElse(null); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderOfferController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderOfferController.java index ab015c2..32e599e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderOfferController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderOfferController.java @@ -40,6 +40,7 @@ import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.social.entity.MessageCause; import de.oaa.xxx.subscription.SubscriptionLimitService; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/keyholder-offers") @@ -56,6 +57,7 @@ public class KeyholderOfferController { private final KeyholderInvitationRepository invitationRepository; private final SystemMessageService systemMessageService; private final SubscriptionLimitService subscriptionLimitService; + private final UserService userService; public KeyholderOfferController( KeyholderOfferRepository offerRepository, @@ -68,7 +70,8 @@ public class KeyholderOfferController { TimeLockServiceFactory timeLockServiceFactory, KeyholderInvitationRepository invitationRepository, SystemMessageService systemMessageService, - SubscriptionLimitService subscriptionLimitService) { + SubscriptionLimitService subscriptionLimitService, + UserService userService) { this.offerRepository = offerRepository; this.templateRepository = templateRepository; this.subscriptionRepository = subscriptionRepository; @@ -80,15 +83,14 @@ public class KeyholderOfferController { this.invitationRepository = invitationRepository; this.systemMessageService = systemMessageService; this.subscriptionLimitService = subscriptionLimitService; + this.userService = userService; } // ── Eigene Angebote ─────────────────────────────────────────────────────── @GetMapping("/mine") public ResponseEntity>> getMyOffers(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List> result = offerRepository.findByOffererId(myId).stream() .map(this::toDto) @@ -102,9 +104,7 @@ public class KeyholderOfferController { @Transactional public ResponseEntity> createOffer( @RequestBody CreateOfferRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); // Limit prüfen @@ -148,9 +148,7 @@ public class KeyholderOfferController { @PathVariable UUID id, @RequestBody CreateOfferRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var offerOpt = offerRepository.findById(id); if (offerOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -181,9 +179,7 @@ public class KeyholderOfferController { @DeleteMapping("/{id}") @Transactional public ResponseEntity deleteOffer(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var offerOpt = offerRepository.findById(id); if (offerOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -198,9 +194,7 @@ public class KeyholderOfferController { @GetMapping("/user/{userId}") public ResponseEntity>> getOffersForUser( @PathVariable UUID userId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List> result = offerRepository.findByOffererId(userId).stream() .map(o -> toPublicDto(o, myId)) @@ -212,9 +206,7 @@ public class KeyholderOfferController { @GetMapping("/public") public ResponseEntity>> getPublicOffers(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); String userGender = me.getGeschlecht() != null ? me.getGeschlecht().name() : null; @@ -244,9 +236,7 @@ public class KeyholderOfferController { @RequestBody JoinOfferRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var offerOpt = offerRepository.findById(id); @@ -344,14 +334,14 @@ public class KeyholderOfferController { systemMessageService.send(myId, offerer.getUserId(), me.getName() + " möchte dein Keyholder-Angebot annehmen und lädt dich als Keyholder für „" + lockName + "\" ein.", - "/einladungen.html", MessageCause.INVITATION); + "/community/einladungen.html", MessageCause.INVITATION); invitationSent = true; } else { // Direktstart: Keyholder wird direkt gesetzt, aber trotzdem benachrichtigen systemMessageService.send(myId, offerer.getUserId(), me.getName() + " hat dein Keyholder-Angebot angenommen und das Lock „" + lockName + "\" gestartet.", - "/keyholder.html", MessageCause.INVITATION); + "/games/chastity/keyholder.html", MessageCause.INVITATION); } // Annahmezähler erhöhen diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceController.java index 4ba0b84..ab319de 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceController.java @@ -22,6 +22,7 @@ import de.oaa.xxx.games.chastity.tasks.AssignedTaskRepository; import de.oaa.xxx.games.chastity.tasks.Task; import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/games/chastity/keyholder/choices") @@ -32,26 +33,27 @@ public class KeyholderTaskChoiceController { private final KeyholderTaskChoiceRepository keyholderTaskChoiceRepository; private final AssignedTaskRepository assignedTaskRepository; private final SystemMessageService systemMessageService; + private final UserService userService; public KeyholderTaskChoiceController(CardlockRepository cardlockRepository, UserRepository userRepository, KeyholderTaskChoiceRepository keyholderTaskChoiceRepository, AssignedTaskRepository assignedTaskRepository, - SystemMessageService systemMessageService) { + SystemMessageService systemMessageService, + UserService userService) { this.cardlockRepository = cardlockRepository; this.userRepository = userRepository; this.keyholderTaskChoiceRepository = keyholderTaskChoiceRepository; this.assignedTaskRepository = assignedTaskRepository; this.systemMessageService = systemMessageService; + this.userService = userService; } // ── Keyholder: ausstehende Aufgaben-Karten-Entscheidungen ───────────────── @GetMapping @Transactional(readOnly = true) public ResponseEntity>> getPendingChoices(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); // Alle Locks bei denen ich Keyholder bin var locks = cardlockRepository.findByKeyholderAndUnlockTimeIsNull(myId); @@ -86,9 +88,7 @@ public class KeyholderTaskChoiceController { @PathVariable int taskIndex, @org.springframework.web.bind.annotation.RequestBody(required = false) PenaltyRequest penalty, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var choiceOpt = keyholderTaskChoiceRepository.findById(choiceId); if (choiceOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -126,7 +126,7 @@ public class KeyholderTaskChoiceController { sendMessage(myId, lock.getLockee(), "Dein Keyholder hat eine Aufgabe für dich ausgewählt.", - "/activelock.html?lockId=" + lock.getLockId()); + "/games/chastity/activelock.html?lockId=" + lock.getLockId()); return ResponseEntity.noContent().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceScheduler.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceScheduler.java index fa76700..86bef6e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceScheduler.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/keyholder/KeyholderTaskChoiceScheduler.java @@ -81,12 +81,12 @@ public class KeyholderTaskChoiceScheduler { sendMessage(lock.getLockee(), "Dein Keyholder hat nicht rechtzeitig gewählt – eine zufällige Aufgabe wurde vergeben: \"" + task.getTitle() + "\"", - "/activelock.html?lockId=" + lock.getLockId()); + "/games/chastity/activelock.html?lockId=" + lock.getLockId()); if (lock.getKeyholder() != null) { sendMessage(lock.getKeyholder(), "Du hast die Aufgabenwahl für \"" + (lock.getName() != null ? lock.getName() : "ein Schloss") + "\" nicht rechtzeitig getroffen. Eine zufällige Aufgabe wurde vergeben.", - "/keyholder.html"); + "/games/chastity/keyholder.html"); } } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/lockee/LockeeInvitationController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/lockee/LockeeInvitationController.java index c1f3672..68d0c4e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/lockee/LockeeInvitationController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/lockee/LockeeInvitationController.java @@ -30,6 +30,7 @@ import de.oaa.xxx.games.chastity.timelock.TimeLockEntity; import de.oaa.xxx.games.chastity.timelock.TimeLockRepository; import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/lockee") @@ -41,6 +42,7 @@ public class LockeeInvitationController { private final TimeLockRepository timeLockRepository; private final UserRepository userRepository; private final SystemMessageService systemMessageService; + private final UserService userService; @Value("${app.base-url:http://localhost:8080}") private String baseUrl; @@ -52,13 +54,15 @@ public class LockeeInvitationController { BaseLockRepository baseLockRepository, TimeLockRepository timeLockRepository, UserRepository userRepository, - SystemMessageService systemMessageService) { + SystemMessageService systemMessageService, + UserService userService) { this.lockeeInvitationRepository = lockeeInvitationRepository; this.cardlockRepository = cardlockRepository; this.baseLockRepository = baseLockRepository; this.timeLockRepository = timeLockRepository; this.userRepository = userRepository; this.systemMessageService = systemMessageService; + this.userService = userService; } private void sendMessage(UUID senderId, UUID receiverId, String text, String targetUrl, de.oaa.xxx.social.entity.MessageCause cause) { @@ -77,11 +81,22 @@ public class LockeeInvitationController { return min + new Random().nextInt(max - min); } + @GetMapping("/invitations/mine/count") + public ResponseEntity countMyInvitations(Principal principal) { + UUID myId = userService.requireUser(principal).getUserId(); + int count = 0; + for (var inv : lockeeInvitationRepository.findByLockeeUserId(myId)) { + var lockOpt = baseLockRepository.findById(inv.getLockId()); + if (lockOpt.isEmpty()) continue; + if (lockOpt.get().getStartTime() != null) continue; + count++; + } + return ResponseEntity.ok(count); + } + @GetMapping("/invitations/mine") public ResponseEntity>> getMyInvitations(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var invitations = lockeeInvitationRepository.findByLockeeUserId(myId); List> result = new ArrayList<>(); @@ -108,9 +123,7 @@ public class LockeeInvitationController { @GetMapping("/invitations/sent") public ResponseEntity>> getSentInvitations(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var invitations = lockeeInvitationRepository.findByKeyholderUserId(myId); List> result = new ArrayList<>(); @@ -138,9 +151,7 @@ public class LockeeInvitationController { @DeleteMapping("/invitations/sent/{token}") @Transactional public ResponseEntity cancelSentInvitation(@PathVariable String token, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var invOpt = lockeeInvitationRepository.findByToken(token); @@ -165,9 +176,7 @@ public class LockeeInvitationController { @GetMapping("/invitation/{token}") public ResponseEntity> getInvitation(@PathVariable String token, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var invOpt = lockeeInvitationRepository.findByToken(token); if (invOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -215,9 +224,7 @@ public class LockeeInvitationController { public ResponseEntity> acceptInvitation(@PathVariable String token, @RequestBody AcceptRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var invOpt = lockeeInvitationRepository.findByToken(token); @@ -273,7 +280,7 @@ public class LockeeInvitationController { sendMessage(myId, inv.getKeyholderUserId(), me.getName() + " hat die Einladung als Lockee für das Lock „" + lockName + "\" angenommen.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); return ResponseEntity.ok(Map.of( "lockId", lock.getLockId().toString(), @@ -284,9 +291,7 @@ public class LockeeInvitationController { @DeleteMapping("/invitation/{token}") @Transactional public ResponseEntity declineInvitation(@PathVariable String token, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var invOpt = lockeeInvitationRepository.findByToken(token); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java index 7cc08b1..b5b7259 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java @@ -46,6 +46,7 @@ import de.oaa.xxx.games.chastity.unlock.TempOpeningReason; import de.oaa.xxx.games.chastity.unlock.UnlockCodeHistoryService; import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/keyholder") @@ -54,6 +55,7 @@ public class TimeLockController { private final TimeLockRepository timeLockRepository; private final TimeLockTemplateRepository templateRepository; private final UserRepository userRepository; + private final UserService userService; private final KeyholderInvitationRepository invitationRepository; private final LockeeInvitationRepository lockeeInvitationRepository; private final SystemMessageService systemMessageService; @@ -66,6 +68,7 @@ public class TimeLockController { public TimeLockController(TimeLockRepository timeLockRepository, TimeLockTemplateRepository templateRepository, UserRepository userRepository, + UserService userService, KeyholderInvitationRepository invitationRepository, LockeeInvitationRepository lockeeInvitationRepository, SystemMessageService systemMessageService, @@ -77,6 +80,7 @@ public class TimeLockController { this.timeLockRepository = timeLockRepository; this.templateRepository = templateRepository; this.userRepository = userRepository; + this.userService = userService; this.invitationRepository = invitationRepository; this.lockeeInvitationRepository = lockeeInvitationRepository; this.systemMessageService = systemMessageService; @@ -104,9 +108,7 @@ public class TimeLockController { public ResponseEntity> createTimeLock( @RequestBody CreateTimeLockRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var templateOpt = templateRepository.findById(req.templateId()); @@ -141,7 +143,7 @@ public class TimeLockController { String lockName = template.getName() != null ? template.getName() : "Unbenanntes Lock"; systemMessageService.send(myId, lockee.getUserId(), me.getName() + " hat dich als Lockee für das Lock „" + lockName + "\" eingeladen.", - "/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); + "/community/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); return ResponseEntity.ok(Map.of( "lockId", lock.getLockId().toString(), @@ -179,7 +181,7 @@ public class TimeLockController { String lockName = template.getName() != null ? template.getName() : "Unbenanntes Lock"; systemMessageService.send(myId, kh.getUserId(), me.getName() + " hat dich als Keyholder*In für das Lock „" + lockName + "\" eingeladen.", - "/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); + "/community/einladungen.html", de.oaa.xxx.social.entity.MessageCause.INVITATION); keyholderPending = true; } @@ -196,9 +198,7 @@ public class TimeLockController { @GetMapping("/timelock/{lockId}") @Transactional public ResponseEntity> getTimeLock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -381,9 +381,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/spin") @Transactional public ResponseEntity> spin(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -433,9 +431,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/relock") @Transactional public ResponseEntity relock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -451,9 +447,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/task/done") @Transactional public ResponseEntity taskDone(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -475,9 +469,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/hygiene/start") @Transactional public ResponseEntity> startHygiene(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -500,9 +492,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/hygiene/end") @Transactional public ResponseEntity> endHygiene(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -524,9 +514,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/verification/start") @Transactional public ResponseEntity> startVerification(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -548,9 +536,7 @@ public class TimeLockController { @RequestParam MultipartFile image, Principal principal) throws IOException { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -561,9 +547,10 @@ public class TimeLockController { if (!found) return ResponseEntity.notFound().build(); if (l.getKeyholder() != null) { + String meName = userRepository.findById(myId).map(u -> u.getName()).orElse(""); systemMessageService.send(myId, l.getKeyholder(), - "📸 " + meOpt.get().getName() + " hat eine Verifikation eingereicht.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "📸 " + meName + " hat eine Verifikation eingereicht.", + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.GAME_STATE); } return ResponseEntity.noContent().build(); } @@ -573,9 +560,7 @@ public class TimeLockController { @DeleteMapping("/timelock/{lockId}") @Transactional public ResponseEntity endLock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -616,9 +601,7 @@ public class TimeLockController { @PatchMapping("/timelock/{lockId}/unlock-time") @Transactional public ResponseEntity setActualUnlockTime(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -639,9 +622,7 @@ public class TimeLockController { @GetMapping("/timelock/as-keyholder") public ResponseEntity>> getTimeLocksAsKeyholder(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var locks = timeLockRepository.findByKeyholderAndStartTimeIsNotNullAndUnlockTimeIsNull(myId); List> result = new ArrayList<>(); @@ -670,9 +651,7 @@ public class TimeLockController { @GetMapping("/timelock/as-keyholder/{lockId}") public ResponseEntity> getTimeLockAsKeyholder( @PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -738,9 +717,7 @@ public class TimeLockController { @Transactional public ResponseEntity requestUnlockAsKeyholder( @PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var lockOpt = timeLockRepository.findById(lockId); if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -760,9 +737,7 @@ public class TimeLockController { @Transactional public ResponseEntity freezeTimeLock(@PathVariable UUID lockId, @RequestBody FreezeRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = timeLockRepository.findById(lockId); @@ -788,7 +763,7 @@ public class TimeLockController { + until.toLocalDate().format(java.time.format.DateTimeFormatter.ofPattern("dd.MM.yyyy")) + " " + until.toLocalTime().format(java.time.format.DateTimeFormatter.ofPattern("HH:mm")) + " Uhr eingefroren.", - "/activetimelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activetimelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -796,9 +771,7 @@ public class TimeLockController { @DeleteMapping("/timelock/as-keyholder/{lockId}/freeze") @Transactional public ResponseEntity unfreezeTimeLock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = timeLockRepository.findById(lockId); @@ -814,7 +787,7 @@ public class TimeLockController { systemMessageService.send(myId, l.getLockee(), me.getName() + " hat dein Lock entfroren.", - "/activetimelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); + "/games/chastity/activetimelock.html?lockId=" + lockId, de.oaa.xxx.social.entity.MessageCause.GAME_STATE); return ResponseEntity.noContent().build(); } @@ -824,9 +797,7 @@ public class TimeLockController { @PostMapping("/timelock/{lockId}/emergency-unlock") @Transactional public ResponseEntity requestEmergencyUnlock(@PathVariable UUID lockId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - var me = meOpt.get(); + var me = userService.requireUser(principal); UUID myId = me.getUserId(); var lockOpt = timeLockRepository.findById(lockId); @@ -849,7 +820,7 @@ public class TimeLockController { } else { systemMessageService.send(myId, l.getKeyholder(), "⚠️ NOTFALL: " + me.getName() + " bittet dringend um Freigabe des Locks. Bitte reagiere innerhalb einer Stunde.", - "/keyholder.html", de.oaa.xxx.social.entity.MessageCause.EMERGENCY); + "/games/chastity/keyholder.html", de.oaa.xxx.social.entity.MessageCause.EMERGENCY); timeLockRepository.save(l); return ResponseEntity.noContent().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockTemplateController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockTemplateController.java index 214d644..7d7bc47 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockTemplateController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockTemplateController.java @@ -6,7 +6,7 @@ import de.oaa.xxx.games.chastity.spinningwheel.SpinningWheelEntry; import de.oaa.xxx.games.chastity.tasks.Task; import de.oaa.xxx.games.chastity.tasks.TaskMode; import de.oaa.xxx.subscription.SubscriptionLimitService; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -19,16 +19,16 @@ import java.util.stream.Collectors; public class TimeLockTemplateController { private final TimeLockTemplateRepository templateRepository; - private final UserRepository userRepository; + private final UserService userService; private final CardlockTemplateRepository cardlockTemplateRepository; private final SubscriptionLimitService limitService; public TimeLockTemplateController(TimeLockTemplateRepository templateRepository, - UserRepository userRepository, + UserService userService, CardlockTemplateRepository cardlockTemplateRepository, SubscriptionLimitService limitService) { this.templateRepository = templateRepository; - this.userRepository = userRepository; + this.userService = userService; this.cardlockTemplateRepository = cardlockTemplateRepository; this.limitService = limitService; } @@ -76,9 +76,7 @@ public class TimeLockTemplateController { @GetMapping public ResponseEntity>> list(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List> result = templateRepository.findByOwner(myId) .stream().map(this::toDto).collect(Collectors.toList()); return ResponseEntity.ok(result); @@ -86,9 +84,7 @@ public class TimeLockTemplateController { @PostMapping public ResponseEntity> create(@RequestBody TemplateRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (req.name() == null || req.name().isBlank()) return ResponseEntity.badRequest().build(); if (req.maxTimeInMinutes() == null || req.maxTimeInMinutes() < 1) return ResponseEntity.badRequest().build(); @@ -109,9 +105,7 @@ public class TimeLockTemplateController { public ResponseEntity> update(@PathVariable UUID id, @RequestBody TemplateRequest req, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var opt = templateRepository.findById(id); if (opt.isEmpty()) return ResponseEntity.notFound().build(); @@ -128,9 +122,7 @@ public class TimeLockTemplateController { @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var opt = templateRepository.findById(id); if (opt.isEmpty()) return ResponseEntity.notFound().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/ttlock/TTLockCallback.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/ttlock/TTLockCallback.java index 565ac91..f616888 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/ttlock/TTLockCallback.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/ttlock/TTLockCallback.java @@ -164,7 +164,7 @@ public class TTLockCallback { userRepository.findById(lock.getKeyholder()).ifPresent(kh -> systemMessageService.send(lock.getLockee(), kh.getUserId(), "Deine Lockee hat ihr Schloss unerlaubt geöffnet!", - "/keyholder.html?lockId=" + lock.getLockId(), + "/games/chastity/keyholder.html?lockId=" + lock.getLockId(), MessageCause.GAME_STATE)); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Aufgabe.java b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Aufgabe.java index b17668f..3053753 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Aufgabe.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Aufgabe.java @@ -3,7 +3,6 @@ package de.oaa.xxx.games.common.aufgaben; import java.util.List; import java.util.UUID; -import de.oaa.xxx.games.bdsm.Mitspieler; import lombok.Getter; import lombok.Setter; @@ -28,7 +27,7 @@ public class Aufgabe { + ", sekunden=" + sekundenVon + "-" + sekundenBis + ", gruppeId=" + gruppeId + "]"; } - public boolean isAufgabePassend(int level, Mitspieler aktiv, Mitspieler passiv) { + public boolean isAufgabePassend(int level, CommonMitspieler aktiv, CommonMitspieler passiv) { if (level != this.level && level - 1 != this.level) { return false; } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/CommonMitspieler.java b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/CommonMitspieler.java new file mode 100644 index 0000000..f8ecd47 --- /dev/null +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/CommonMitspieler.java @@ -0,0 +1,6 @@ +package de.oaa.xxx.games.common.aufgaben; + +public interface CommonMitspieler { + + boolean isVerfuegbar(Werkzeug werkzeug); +} diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Finisher.java b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Finisher.java index 2b8bec7..1a47182 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Finisher.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Finisher.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.UUID; import de.oaa.xxx.games.bdsm.GeschlechtEnum; -import de.oaa.xxx.games.bdsm.Mitspieler; import lombok.Getter; import lombok.Setter; @@ -26,7 +25,7 @@ public class Finisher { return "Finisher[id=" + finisherId + ", kurzText=" + kurzText + ", geschlecht=" + geschlecht + ", gruppeId=" + gruppeId + "]"; } - public boolean isAufgabePassend(Mitspieler aktiv, Mitspieler passiv) { + public boolean isAufgabePassend(CommonMitspieler aktiv, CommonMitspieler passiv) { if (benoetigtPassiv != null) { for (Werkzeug werkzeug : benoetigtPassiv) { if (!passiv.isVerfuegbar(werkzeug)) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Sperre.java b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Sperre.java index 48727d1..45c5074 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Sperre.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Sperre.java @@ -3,7 +3,7 @@ package de.oaa.xxx.games.common.aufgaben; import java.util.List; import java.util.UUID; -import de.oaa.xxx.games.bdsm.Mitspieler; +import de.oaa.xxx.games.bdsm.BdsmMitspieler; import lombok.Getter; import lombok.Setter; @@ -27,7 +27,7 @@ public class Sperre { + ", minuten=" + minutenVon + "-" + minutenBis + ", fuer=" + sperreFuer + ", gruppeId=" + gruppeId + "]"; } - public boolean isAufgabePassend(Mitspieler passiv) { + public boolean isAufgabePassend(BdsmMitspieler passiv) { for (Werkzeug werkzeug : sperreFuer) { if (!passiv.isVerfuegbar(werkzeug)) { return false; diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Strafe.java b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Strafe.java index a795d87..e9365ff 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Strafe.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/common/aufgaben/Strafe.java @@ -3,7 +3,7 @@ package de.oaa.xxx.games.common.aufgaben; import java.util.List; import java.util.UUID; -import de.oaa.xxx.games.bdsm.Mitspieler; +import de.oaa.xxx.games.bdsm.BdsmMitspieler; import lombok.Getter; import lombok.Setter; @@ -22,7 +22,7 @@ public class Strafe { private List benoetigtPassiv; private List benoetigteToys; - public boolean isAufgabePassend(int level, Mitspieler aktiv, Mitspieler passiv) { + public boolean isAufgabePassend(int level, BdsmMitspieler aktiv, BdsmMitspieler passiv) { if (level != this.level && level - 1 != this.level) { return false; } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/history/GameHistoryController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/history/GameHistoryController.java index 8f39527..8690b5c 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/history/GameHistoryController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/history/GameHistoryController.java @@ -1,6 +1,7 @@ package de.oaa.xxx.games.history; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; @@ -20,17 +21,18 @@ public class GameHistoryController { private final UserRepository userRepository; private final GameHistoryRepository gameHistoryRepository; + private final UserService userService; - public GameHistoryController(UserRepository userRepository, GameHistoryRepository gameHistoryRepository) { + public GameHistoryController(UserRepository userRepository, GameHistoryRepository gameHistoryRepository, UserService userService) { this.userRepository = userRepository; this.gameHistoryRepository = gameHistoryRepository; + this.userService = userService; } @GetMapping @Transactional(readOnly = true) public ResponseEntity>> get(@RequestParam UUID userId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); + userService.requireUser(principal); var result = gameHistoryRepository.findByParticipantUserId(userId).stream() .map(e -> { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaGameDurchfuehren.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaGameDurchfuehren.java index 4fdbe45..4a262b2 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaGameDurchfuehren.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaGameDurchfuehren.java @@ -1,16 +1,16 @@ package de.oaa.xxx.games.vanilla; -import com.fasterxml.jackson.databind.ObjectMapper; -import de.oaa.xxx.games.common.aufgaben.Aufgabe; -import de.oaa.xxx.games.common.aufgaben.AufgabenList; -import de.oaa.xxx.games.bdsm.GeschlechtEnum; -import de.oaa.xxx.games.bdsm.RolleEnum; -import de.oaa.xxx.games.vanilla.entity.VanillaGameEntity; - import java.util.ArrayList; import java.util.List; import java.util.Random; +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.oaa.xxx.games.bdsm.GeschlechtEnum; +import de.oaa.xxx.games.common.aufgaben.Aufgabe; +import de.oaa.xxx.games.common.aufgaben.AufgabenList; +import de.oaa.xxx.games.vanilla.entity.VanillaGameEntity; + public class VanillaGameDurchfuehren { private final AufgabenList aufgabenList; @@ -34,13 +34,14 @@ public class VanillaGameDurchfuehren { public VanillaAufgabeAnzeige getNext() { checkLevel(); if (level == 6) return null; + // Fallback + VanillaMitspieler aktiv = findeMitspielerMitRolle(); + VanillaMitspieler passiv = findeMitspielerMitRolle(aktiv); - VanillaAufgabeAnzeige anzeige = findeAufgabe(); + VanillaAufgabeAnzeige anzeige = findeAufgabe(aktiv, passiv); if (anzeige != null) return anzeige; - // Fallback - VanillaMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV); - VanillaMitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv); + VanillaAufgabeAnzeige fallback = new VanillaAufgabeAnzeige(); fallback.setNameAktiverMitspieler(aktiv != null ? aktiv.getName() : ""); if (aktiv != null) { fallback.setMitspielerId(aktiv.getId()); fallback.setEigenesGeraet(aktiv.isEigenesGeraet()); } @@ -54,10 +55,10 @@ public class VanillaGameDurchfuehren { public List getFinisher() { var list = new ArrayList(); List.of(GeschlechtEnum.WEIBLICH, GeschlechtEnum.DIVERS, GeschlechtEnum.MAENNLICH).forEach(geschlecht -> { - mitspieler.stream().filter(m -> geschlecht == m.getGeschlecht()).toList().forEach(cumming -> { - var partner = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, cumming); + mitspieler.stream().forEach(cumming -> { + var partner = findeMitspielerMitRolle(cumming); var finishers = aufgabenList.getFinisher().stream() - .filter(f -> geschlecht == f.getGeschlecht() && f.isAufgabePassend(partner != null ? toMitspielerBdsm(partner) : null, toMitspielerBdsm(cumming))) + .filter(f -> geschlecht == f.getGeschlecht() && f.isAufgabePassend(cumming, partner)) .toList(); VanillaAufgabeAnzeige anzeige = new VanillaAufgabeAnzeige(); anzeige.setNameAktiverMitspieler(cumming.getName()); @@ -82,14 +83,9 @@ public class VanillaGameDurchfuehren { } } - private VanillaAufgabeAnzeige findeAufgabe() { - VanillaMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV); - if (aktiv == null) return null; - VanillaMitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv); - de.oaa.xxx.games.bdsm.Mitspieler aktivBdsm = toMitspielerBdsm(aktiv); - de.oaa.xxx.games.bdsm.Mitspieler passivBdsm = passiv != null ? toMitspielerBdsm(passiv) : null; + private VanillaAufgabeAnzeige findeAufgabe(VanillaMitspieler aktiv, VanillaMitspieler passiv) { List passende = aufgabenList.getAufgaben().stream() - .filter(a -> a.isAufgabePassend(level, aktivBdsm, passivBdsm != null ? passivBdsm : aktivBdsm)) + .filter(a -> a.isAufgabePassend(level, aktiv, passiv)) .toList(); if (passende.isEmpty()) return null; Aufgabe aufgabe = passende.get(new Random().nextInt(passende.size())); @@ -104,23 +100,18 @@ public class VanillaGameDurchfuehren { return anzeige; } - private VanillaMitspieler findeMitspielerMitRolle(RolleEnum rolle) { return findeMitspielerMitRolle(rolle, null); } - private VanillaMitspieler findeMitspielerMitRolle(RolleEnum rolle, VanillaMitspieler ausschliessen) { + private VanillaMitspieler findeMitspielerMitRolle() { + return findeMitspielerMitRolle(null); + } + + private VanillaMitspieler findeMitspielerMitRolle(VanillaMitspieler ausschliessen) { List kandidaten = mitspieler.stream() - .filter(m -> m.getRollen().contains(rolle) && !m.equals(ausschliessen)) + .filter(m -> !m.equals(ausschliessen)) .toList(); if (kandidaten.isEmpty()) return null; return kandidaten.get(new Random().nextInt(kandidaten.size())); } - private de.oaa.xxx.games.bdsm.Mitspieler toMitspielerBdsm(VanillaMitspieler vm) { - de.oaa.xxx.games.bdsm.Mitspieler m = new de.oaa.xxx.games.bdsm.Mitspieler(); - m.setId(vm.getId()); m.setName(vm.getName()); m.setGeschlecht(vm.getGeschlecht()); - m.setRollen(vm.getRollen()); m.setSpieltMit(vm.getSpieltMit()); - m.setVerfuegbareWerkzeuge(vm.getVerfuegbareWerkzeuge()); m.setEigenesGeraet(vm.isEigenesGeraet()); - return m; - } - private String getAnzeigeText(String text, String aktiv, String passiv) { if (text == null) return ""; return text.replace("{AKTIV}", aktiv != null ? aktiv : "").replace("{PASSIV}", passiv != null ? passiv : ""); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaMitspieler.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaMitspieler.java index 7c50551..cfa46be 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaMitspieler.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/VanillaMitspieler.java @@ -1,20 +1,17 @@ package de.oaa.xxx.games.vanilla; -import de.oaa.xxx.games.bdsm.GeschlechtEnum; -import de.oaa.xxx.games.bdsm.RolleEnum; -import de.oaa.xxx.games.common.aufgaben.Werkzeug; -import lombok.Getter; -import lombok.Setter; import java.util.List; import java.util.UUID; +import de.oaa.xxx.games.common.aufgaben.CommonMitspieler; +import de.oaa.xxx.games.common.aufgaben.Werkzeug; +import lombok.Getter; +import lombok.Setter; + @Getter @Setter -public class VanillaMitspieler { +public class VanillaMitspieler implements CommonMitspieler { private UUID id; private UUID userId; private String name; - private GeschlechtEnum geschlecht; - private List rollen; - private List spieltMit; private List verfuegbareWerkzeuge; private boolean eigenesGeraet; diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAboController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAboController.java index 93be936..ccd6672 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAboController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAboController.java @@ -7,7 +7,7 @@ import de.oaa.xxx.games.common.entity.GruppenAboEntity; import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository; import de.oaa.xxx.games.common.repository.GruppenAboRepository; import de.oaa.xxx.user.UserEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; @@ -37,14 +37,14 @@ public class VanillaAboController { private final GruppenAboRepository aboRepository; private final AufgabenGruppeRepository gruppeRepository; - private final UserRepository userRepository; + private final UserService userService; public VanillaAboController(GruppenAboRepository aboRepository, AufgabenGruppeRepository gruppeRepository, - UserRepository userRepository) { + UserService userService) { this.aboRepository = aboRepository; this.gruppeRepository = gruppeRepository; - this.userRepository = userRepository; + this.userService = userService; } // ── Abonnierte Gruppen laden (nur vanilla-safe) ── @@ -54,8 +54,7 @@ public class VanillaAboController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "" + DEFAULT_PAGE_SIZE) int size, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); List dtos = aboRepository.findByUserId(user.getUserId()).stream() .map(GruppenAboEntity::getAufgabenGruppe) @@ -76,8 +75,7 @@ public class VanillaAboController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "" + DISCOVER_PAGE_SIZE) int size, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); String namePattern = name != null && !name.isBlank() ? "%" + name.trim() + "%" : null; @@ -95,8 +93,7 @@ public class VanillaAboController { @PostMapping("/{gruppenId}") public ResponseEntity subscribe(@PathVariable UUID gruppenId, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); AufgabenGruppeEntity gruppe = gruppeRepository.findById(gruppenId).orElse(null); if (gruppe == null || gruppe.isPrivateGruppe() || user.getUserId().equals(gruppe.getUserId())) { @@ -122,8 +119,7 @@ public class VanillaAboController { @DeleteMapping("/{gruppenId}") public ResponseEntity unsubscribe(@PathVariable UUID gruppenId, Principal principal) { - UserEntity user = resolveUser(principal); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); AufgabenGruppeEntity gruppe = gruppeRepository.findById(gruppenId).orElse(null); if (gruppe == null) return ResponseEntity.noContent().build(); @@ -154,7 +150,4 @@ public class VanillaAboController { return result; } - private UserEntity resolveUser(Principal principal) { - return userRepository.findByEmail(principal.getName()).orElse(null); - } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabeController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabeController.java index e4c81b0..a54d721 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabeController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabeController.java @@ -9,7 +9,7 @@ import de.oaa.xxx.games.common.repository.AufgabeRepository; import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository; import de.oaa.xxx.games.common.repository.ToyRepository; import de.oaa.xxx.subscription.SubscriptionLimitService; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -39,18 +39,18 @@ public class VanillaAufgabeController { private final AufgabeRepository aufgabeRepository; private final AufgabenGruppeRepository gruppeRepository; private final ToyRepository toyRepository; - private final UserRepository userRepository; + private final UserService userService; private final SubscriptionLimitService limitService; public VanillaAufgabeController(AufgabeRepository aufgabeRepository, AufgabenGruppeRepository gruppeRepository, ToyRepository toyRepository, - UserRepository userRepository, + UserService userService, SubscriptionLimitService limitService) { this.aufgabeRepository = aufgabeRepository; this.gruppeRepository = gruppeRepository; this.toyRepository = toyRepository; - this.userRepository = userRepository; + this.userService = userService; this.limitService = limitService; } @@ -70,9 +70,7 @@ public class VanillaAufgabeController { if (gruppeEntity == null) { return ResponseEntity.badRequest().build(); } - var ownerOpt = userRepository.findByEmail(principal.getName()); - int limit = ownerOpt.map(u -> limitService.maxTasksPerGroup(u.getUserId())) - .orElse(SubscriptionLimitService.STANDARD_MAX_TASKS_PER_GROUP); + int limit = limitService.maxTasksPerGroup(userService.requireUser(principal).getUserId()); if (gruppeEntity.getAufgaben().size() >= limit) { return ResponseEntity.status(409).build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabenGruppeController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabenGruppeController.java index 64755d1..87a87f4 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabenGruppeController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaAufgabenGruppeController.java @@ -10,7 +10,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -36,7 +35,7 @@ import de.oaa.xxx.games.common.repository.SperreRepository; import de.oaa.xxx.games.common.repository.StrafeRepository; import de.oaa.xxx.subscription.SubscriptionLimitService; import de.oaa.xxx.user.UserEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/vanilla/gruppe") @@ -51,29 +50,29 @@ public class VanillaAufgabenGruppeController { private final StrafeRepository strafeRepository; private final SperreRepository sperreRepository; private final FinisherRepository finisherRepository; - private final UserRepository userRepository; private final GruppenAboRepository aboRepository; private final AufgabenGruppeService aufgabenGruppeService; private final SubscriptionLimitService limitService; + private final UserService userService; public VanillaAufgabenGruppeController(AufgabenGruppeRepository gruppeRepository, AufgabeRepository aufgabeRepository, StrafeRepository strafeRepository, SperreRepository sperreRepository, FinisherRepository finisherRepository, - UserRepository userRepository, GruppenAboRepository aboRepository, AufgabenGruppeService aufgabenGruppeService, - SubscriptionLimitService limitService) { + SubscriptionLimitService limitService, + UserService userService) { this.gruppeRepository = gruppeRepository; this.aufgabeRepository = aufgabeRepository; this.strafeRepository = strafeRepository; this.sperreRepository = sperreRepository; this.finisherRepository = finisherRepository; - this.userRepository = userRepository; this.aboRepository = aboRepository; this.aufgabenGruppeService = aufgabenGruppeService; this.limitService = limitService; + this.userService = userService; } // ── Paginierte Listen ── @@ -120,8 +119,8 @@ public class VanillaAufgabenGruppeController { // ── Bestehende Endpunkte ── @GetMapping("/all") - public ResponseEntity getAll(@RequestParam(required = false) String search) { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + public ResponseEntity getAll(@RequestParam(required = false) String search, Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); String searchPattern = search != null ? "%" + search + "%" : null; AufgabenGruppeList list = new AufgabenGruppeList(); list.setGruppen(gruppeRepository.listVanillaSafeWithUserAndSearch(userId, searchPattern, PageRequest.of(0, 500)) @@ -267,7 +266,8 @@ public class VanillaAufgabenGruppeController { // ── Hilfsmethoden ── private UserEntity resolveUser(Principal principal) { - return userRepository.findByEmail(principal.getName()).orElse(null); + if (principal == null) return null; + return userService.requireUser(principal); } private AufgabenGruppePage manualPage(java.util.List all, int page, int size) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaEinladungController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaEinladungController.java index 160f71b..3006053 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaEinladungController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaEinladungController.java @@ -26,6 +26,7 @@ import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.social.entity.MessageCause; import de.oaa.xxx.social.repository.FriendshipRepository; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/vanilla/einladung") @@ -36,15 +37,18 @@ public class VanillaEinladungController { private final UserRepository userRepository; private final FriendshipRepository friendshipRepository; private final SystemMessageService systemMessageService; + private final UserService userService; public VanillaEinladungController(VanillaEinladungRepository einladungRepository, UserRepository userRepository, FriendshipRepository friendshipRepository, - SystemMessageService systemMessageService) { + SystemMessageService systemMessageService, + UserService userService) { this.einladungRepository = einladungRepository; this.userRepository = userRepository; this.friendshipRepository = friendshipRepository; this.systemMessageService = systemMessageService; + this.userService = userService; } record EinladungRequest(UUID setupId, int slotIndex, UUID inviteeId) {} @@ -52,8 +56,7 @@ public class VanillaEinladungController { record SpielerDatenRequest(String spielerDatenJson) {} private UUID currentUserId(Principal principal) { - return userRepository.findByEmail(principal.getName()) - .map(u -> u.getUserId()).orElse(null); + return userService.requireUser(principal).getUserId(); } @PostMapping @@ -107,7 +110,7 @@ public class VanillaEinladungController { systemMessageService.send( inviterId, req.inviteeId(), inviterName + " hat dich zum Vanilla Game eingeladen.", - "/einladungen.html", + "/community/einladungen.html", MessageCause.INVITATION ); @@ -127,7 +130,7 @@ public class VanillaEinladungController { String inviterName = userRepository.findById(userId).map(u -> u.getName()).orElse("Jemand"); systemMessageService.send(userId, e.getInviteeId(), inviterName + " hat die Vanilla-Spieleinladung zurückgezogen.", - "/einladungen.html", MessageCause.INVITATION); + "/community/einladungen.html", MessageCause.INVITATION); return ResponseEntity.accepted().build(); } @@ -150,6 +153,13 @@ public class VanillaEinladungController { .orElse(ResponseEntity.noContent().build()); } + @GetMapping("/pending/count") + public ResponseEntity getPendingCount(Principal principal) { + UUID userId = currentUserId(principal); + if (userId == null) return ResponseEntity.status(401).build(); + return ResponseEntity.ok(einladungRepository.findByInviteeIdAndStatus(userId, Status.PENDING).size()); + } + @GetMapping("/pending") public ResponseEntity>> getPending(Principal principal) { UUID userId = currentUserId(principal); @@ -241,6 +251,7 @@ public class VanillaEinladungController { m.put("sessionId", e.getSessionId()); m.put("bereit", e.isBereit()); m.put("spielerDatenJson", e.getSpielerDatenJson()); + m.put("createdAt", e.getCreatedAt().toString()); userRepository.findById(e.getInviteeId()).ifPresent(u -> m.put("inviteeName", u.getName())); return m; } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaFavoritController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaFavoritController.java index c008c0a..0b171e4 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaFavoritController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaFavoritController.java @@ -5,11 +5,11 @@ import de.oaa.xxx.games.common.aufgaben.FavoritList; import de.oaa.xxx.games.common.entity.FavoritEntity; import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository; import de.oaa.xxx.games.common.repository.FavoritRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import java.security.Principal; import java.util.List; import java.util.UUID; @@ -32,11 +33,14 @@ public class VanillaFavoritController { private final FavoritRepository favoritRepository; private final AufgabenGruppeRepository gruppeRepository; + private final UserService userService; public VanillaFavoritController(FavoritRepository favoritRepository, - AufgabenGruppeRepository gruppeRepository) { + AufgabenGruppeRepository gruppeRepository, + UserService userService) { this.favoritRepository = favoritRepository; this.gruppeRepository = gruppeRepository; + this.userService = userService; } @GetMapping("/{favoritId}") @@ -47,8 +51,8 @@ public class VanillaFavoritController { } @GetMapping - public ResponseEntity all() { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + public ResponseEntity all(Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); List entities = favoritRepository.findByUserId(userId); FavoritList result = new FavoritList(); // Only return favorites pointing to vanilla-safe groups @@ -62,8 +66,8 @@ public class VanillaFavoritController { } @PostMapping - public ResponseEntity create(@RequestBody Favorit favorit) { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + public ResponseEntity create(@RequestBody Favorit favorit, Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); if (favorit.getAufgabenGruppeId() == null) { return ResponseEntity.badRequest().build(); } @@ -87,9 +91,9 @@ public class VanillaFavoritController { } @DeleteMapping - public ResponseEntity delete(@RequestBody Favorit favorit) { + public ResponseEntity delete(@RequestBody Favorit favorit, Principal principal) { try { - UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + UUID userId = userService.requireUser(principal).getUserId(); favoritRepository.findByUserIdAndAufgabenGruppeId(userId, favorit.getAufgabenGruppeId()) .forEach(favoritRepository::delete); return ResponseEntity.accepted().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaGameController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaGameController.java index 12c8ae8..d1da618 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaGameController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaGameController.java @@ -41,7 +41,7 @@ import de.oaa.xxx.games.vanilla.repository.VanillaGameRepository; import de.oaa.xxx.games.vanilla.repository.VanillaMitspielerRepository; import de.oaa.xxx.social.SystemMessageService; import de.oaa.xxx.social.entity.MessageCause; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; @RestController @RequestMapping("/vanilla") @@ -58,22 +58,23 @@ public class VanillaGameController { private final VanillaGameRepository sessionRepository; private final VanillaMitspielerRepository mitspielerRepository; private final VanillaEinladungRepository einladungRepository; - private final UserRepository userRepository; + private final ObjectMapper objectMapper; private final SystemMessageService systemMessageService; + private final UserService userService; public VanillaGameController(VanillaGameRepository sessionRepository, VanillaMitspielerRepository mitspielerRepository, VanillaEinladungRepository einladungRepository, - UserRepository userRepository, ObjectMapper objectMapper, - SystemMessageService systemMessageService) { + SystemMessageService systemMessageService, + UserService userService) { this.sessionRepository = sessionRepository; this.mitspielerRepository = mitspielerRepository; this.einladungRepository = einladungRepository; - this.userRepository = userRepository; this.objectMapper = objectMapper; this.systemMessageService = systemMessageService; + this.userService = userService; } @GetMapping("/{sessionId}") @@ -91,10 +92,8 @@ public class VanillaGameController { } @PostMapping - public ResponseEntity create(@RequestBody VanillaGame session) { - String email = (String) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - UUID userId = userRepository.findByEmail(email).map(u -> u.getUserId()).orElse(null); - if (userId == null) return ResponseEntity.status(401).build(); + public ResponseEntity create(@RequestBody VanillaGame session, Principal principal) { + UUID userId = userService.requireUser(principal).getUserId(); var existingOpt = sessionRepository.findByUserId(userId); if (existingOpt.isPresent()) { VanillaGameEntity existing = existingOpt.get(); @@ -151,8 +150,7 @@ public class VanillaGameController { @DeleteMapping("/{sessionId}/verlassen") public ResponseEntity verlasseSpiel(@PathVariable UUID sessionId, Principal principal) { - UUID userId = userRepository.findByEmail(principal.getName()).map(u -> u.getUserId()).orElse(null); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); VanillaGameEntity session = sessionRepository.findById(sessionId).orElse(null); if (session == null) return ResponseEntity.notFound().build(); @@ -232,9 +230,7 @@ public class VanillaGameController { @PostMapping("/{sessionId}/mitspieler") public ResponseEntity addMitspieler(@RequestBody VanillaMitspieler mitspieler, @PathVariable UUID sessionId) { - if (mitspieler.getName() == null || mitspieler.getGeschlecht() == null || mitspieler.getRollen() == null - || mitspieler.getRollen().isEmpty() || mitspieler.getSpieltMit() == null || mitspieler.getSpieltMit().isEmpty() - || mitspieler.getVerfuegbareWerkzeuge() == null || mitspieler.getVerfuegbareWerkzeuge().isEmpty()) { + if (mitspieler.getName() == null || mitspieler.getVerfuegbareWerkzeuge() == null || mitspieler.getVerfuegbareWerkzeuge().isEmpty()) { return ResponseEntity.badRequest().build(); } VanillaGameEntity session = sessionRepository.findById(sessionId).orElse(null); @@ -247,10 +243,7 @@ public class VanillaGameController { } VanillaMitspielerEntity entity = new VanillaMitspielerEntity(); entity.setMitspielerId(UUID.randomUUID()); - entity.setGeschlecht(mitspieler.getGeschlecht()); entity.setName(mitspieler.getName()); - entity.setRollen(mitspieler.getRollen()); - entity.setSpieltMit(mitspieler.getSpieltMit()); entity.setWerkzeuge(new ArrayList<>(mitspieler.getVerfuegbareWerkzeuge())); entity.setUserId(mitspieler.getUserId()); entity.setEigenesGeraet(mitspieler.isEigenesGeraet()); @@ -291,8 +284,7 @@ public class VanillaGameController { @GetMapping("/{sessionId}/mitspieler/me") public ResponseEntity> getMeinMitspieler(@PathVariable UUID sessionId, Principal principal) { - UUID userId = userRepository.findByEmail(principal.getName()).map(u -> u.getUserId()).orElse(null); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); VanillaGameEntity session = sessionRepository.findById(sessionId).orElse(null); if (session == null) return ResponseEntity.notFound().build(); return session.getMitspieler().stream() @@ -382,10 +374,7 @@ public class VanillaGameController { mp.put("mitspielerId", m.getMitspielerId()); mp.put("name", m.getName()); mp.put("userId", m.getUserId()); - mp.put("geschlecht", m.getGeschlecht()); - mp.put("rollen", m.getRollen()); mp.put("werkzeuge", m.getWerkzeuge()); - mp.put("spieltMit", m.getSpieltMit()); mp.put("eigenesGeraet", m.isEigenesGeraet()); return mp; }).toList(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaSetupDraftController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaSetupDraftController.java index e7d6765..2926253 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaSetupDraftController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaSetupDraftController.java @@ -2,7 +2,7 @@ package de.oaa.xxx.games.vanilla.controller; import de.oaa.xxx.games.vanilla.entity.VanillaSetupDraftEntity; import de.oaa.xxx.games.vanilla.repository.VanillaSetupDraftRepository; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -19,25 +19,20 @@ import java.util.UUID; public class VanillaSetupDraftController { private final VanillaSetupDraftRepository draftRepository; - private final UserRepository userRepository; + private final UserService userService; - public VanillaSetupDraftController(VanillaSetupDraftRepository draftRepository, UserRepository userRepository) { + public VanillaSetupDraftController(VanillaSetupDraftRepository draftRepository, UserService userService) { this.draftRepository = draftRepository; - this.userRepository = userRepository; + this.userService = userService; } record DraftRequest(String setupId, String settingsJson, String setupJson, String gruppenJson) {} - private UUID currentUserId(Principal principal) { - return userRepository.findByEmail(principal.getName()).map(u -> u.getUserId()).orElse(null); - } - @GetMapping public ResponseEntity> getDraft( @RequestParam(required = false) String setupId, Principal principal) { - UUID userId = currentUserId(principal); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); var lookup = (setupId != null && !setupId.isBlank()) ? draftRepository.findBySetupId(setupId) : draftRepository.findByUserId(userId); @@ -55,8 +50,7 @@ public class VanillaSetupDraftController { @PutMapping public ResponseEntity saveDraft(@RequestBody DraftRequest req, Principal principal) { - UUID userId = currentUserId(principal); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); VanillaSetupDraftEntity d = draftRepository.findByUserId(userId) .orElseGet(() -> { VanillaSetupDraftEntity n = new VanillaSetupDraftEntity(); n.setUserId(userId); return n; }); if (req.setupId() != null) d.setSetupId(req.setupId()); @@ -70,8 +64,7 @@ public class VanillaSetupDraftController { @DeleteMapping public ResponseEntity deleteDraft(Principal principal) { - UUID userId = currentUserId(principal); - if (userId == null) return ResponseEntity.status(401).build(); + UUID userId = userService.requireUser(principal).getUserId(); draftRepository.findByUserId(userId).ifPresent(draftRepository::delete); return ResponseEntity.accepted().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaToyController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaToyController.java index 497e883..b62275a 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaToyController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/controller/VanillaToyController.java @@ -8,7 +8,7 @@ import de.oaa.xxx.games.common.repository.GruppenAboRepository; import de.oaa.xxx.games.common.repository.ToyRepository; import de.oaa.xxx.subscription.SubscriptionLimitService; import de.oaa.xxx.user.UserEntity; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -45,16 +45,16 @@ public class VanillaToyController { private static final int DEFAULT_PAGE_SIZE = 12; private final ToyRepository toyRepository; - private final UserRepository userRepository; + private final UserService userService; private final GruppenAboRepository aboRepository; private final SubscriptionLimitService limitService; public VanillaToyController(ToyRepository toyRepository, - UserRepository userRepository, + UserService userService, GruppenAboRepository aboRepository, SubscriptionLimitService limitService) { this.toyRepository = toyRepository; - this.userRepository = userRepository; + this.userService = userService; this.aboRepository = aboRepository; this.limitService = limitService; } @@ -64,10 +64,7 @@ public class VanillaToyController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "" + DEFAULT_PAGE_SIZE) int size, Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); Page result = toyRepository.findByUserId( user.getUserId(), PageRequest.of(page, size, Sort.by("name"))); return ResponseEntity.ok(toToyPage(result)); @@ -88,8 +85,7 @@ public class VanillaToyController { */ @GetMapping("/available") public ResponseEntity> available(Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) return ResponseEntity.status(401).build(); + UserEntity user = userService.requireUser(principal); List own = toyRepository.findByUserId(user.getUserId(), PageRequest.of(0, 500, Sort.by("name"))).getContent(); List system = toyRepository.findByUserIdIsNull(PageRequest.of(0, 500, Sort.by("name"))).getContent(); @@ -130,10 +126,7 @@ public class VanillaToyController { if (toy.getName() == null || toy.getName().isBlank()) { return ResponseEntity.badRequest().build(); } - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); if (toyRepository.existsByNameIgnoreCaseAndUserIdIsNull(toy.getName()) || toyRepository.existsByNameIgnoreCaseAndUserId(toy.getName(), user.getUserId())) { return ResponseEntity.status(409) @@ -156,10 +149,7 @@ public class VanillaToyController { @PostMapping("/copy/{toyId}") public ResponseEntity copy(@PathVariable UUID toyId, Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); ToyEntity source = toyRepository.findById(toyId).orElse(null); if (source == null) { return ResponseEntity.notFound().build(); @@ -188,10 +178,7 @@ public class VanillaToyController { if (toy.getName() == null || toy.getName().isBlank()) { return ResponseEntity.badRequest().build(); } - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); ToyEntity entity = toyRepository.findById(toyId).orElse(null); if (entity == null) { return ResponseEntity.notFound().build(); @@ -217,10 +204,7 @@ public class VanillaToyController { @DeleteMapping("/{toyId}") public ResponseEntity delete(@PathVariable UUID toyId, Principal principal) { - UserEntity user = userRepository.findByEmail(principal.getName()).orElse(null); - if (user == null) { - return ResponseEntity.status(401).build(); - } + UserEntity user = userService.requireUser(principal); ToyEntity toy = toyRepository.findById(toyId).orElse(null); if (toy == null) { return ResponseEntity.noContent().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/entity/VanillaMitspielerEntity.java b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/entity/VanillaMitspielerEntity.java index 0bd9cd2..b2d7121 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/entity/VanillaMitspielerEntity.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/vanilla/entity/VanillaMitspielerEntity.java @@ -1,41 +1,54 @@ package de.oaa.xxx.games.vanilla.entity; -import de.oaa.xxx.games.bdsm.GeschlechtEnum; -import de.oaa.xxx.games.bdsm.RolleEnum; -import de.oaa.xxx.games.common.aufgaben.Werkzeug; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; import java.util.ArrayList; import java.util.List; import java.util.UUID; -@Getter @Setter @Entity @Table(name = "vanilla_mitspieler") -public class VanillaMitspielerEntity { - @Id @Column private UUID mitspielerId; - @Column private UUID userId; - @Column private boolean eigenesGeraet; - @Column private String name; - @Enumerated(EnumType.STRING) @Column private GeschlechtEnum geschlecht; - @Enumerated(EnumType.STRING) - @ElementCollection(targetClass = Werkzeug.class, fetch = FetchType.EAGER) - @CollectionTable(name = "vanilla_mitspieler_werkzeuge", joinColumns = @JoinColumn(name = "mitspielerId")) - @Column(name = "werkzeug") private List werkzeuge = new ArrayList<>(); - @Enumerated(EnumType.STRING) - @ElementCollection(targetClass = GeschlechtEnum.class, fetch = FetchType.EAGER) - @CollectionTable(name = "vanilla_mitspieler_spieltMit", joinColumns = @JoinColumn(name = "mitspielerId")) - @Column(name = "geschlecht") private List spieltMit = new ArrayList<>(); - @Enumerated(EnumType.STRING) - @ElementCollection(targetClass = RolleEnum.class, fetch = FetchType.EAGER) - @CollectionTable(name = "vanilla_mitspieler_rollen", joinColumns = @JoinColumn(name = "mitspielerId")) - @Column(name = "rolle") private List rollen = new ArrayList<>(); - @ManyToOne @JoinColumn(name = "sessionId", nullable = false) private VanillaGameEntity session; +import de.oaa.xxx.games.common.aufgaben.Werkzeug; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; - public de.oaa.xxx.games.vanilla.VanillaMitspieler toMitspieler() { - de.oaa.xxx.games.vanilla.VanillaMitspieler m = new de.oaa.xxx.games.vanilla.VanillaMitspieler(); - m.setGeschlecht(geschlecht); m.setId(mitspielerId); m.setUserId(userId); - m.setEigenesGeraet(eigenesGeraet); m.setName(name); m.setRollen(rollen); - m.setSpieltMit(spieltMit); m.setVerfuegbareWerkzeuge(new ArrayList<>(werkzeuge)); - return m; - } +@Getter +@Setter +@Entity +@Table(name = "vanilla_mitspieler") +public class VanillaMitspielerEntity { + @Id + @Column + private UUID mitspielerId; + @Column + private UUID userId; + @Column + private boolean eigenesGeraet; + @Column + private String name; + @Enumerated(EnumType.STRING) + @ElementCollection(targetClass = Werkzeug.class, fetch = FetchType.EAGER) + @CollectionTable(name = "vanilla_mitspieler_werkzeuge", joinColumns = @JoinColumn(name = "mitspielerId")) + @Column(name = "werkzeug") + private List werkzeuge = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "sessionId", nullable = false) + private VanillaGameEntity session; + + public de.oaa.xxx.games.vanilla.VanillaMitspieler toMitspieler() { + de.oaa.xxx.games.vanilla.VanillaMitspieler m = new de.oaa.xxx.games.vanilla.VanillaMitspieler(); + m.setId(mitspielerId); + m.setUserId(userId); + m.setEigenesGeraet(eigenesGeraet); + m.setName(name); + m.setVerfuegbareWerkzeuge(new ArrayList<>(werkzeuge)); + return m; + } } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppeController.java b/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppeController.java index 0d48563..a669b18 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppeController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppeController.java @@ -7,6 +7,7 @@ import de.oaa.xxx.social.entity.KommentarEntity; import de.oaa.xxx.social.repository.KommentarRepository; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -32,6 +33,7 @@ public class GruppeController { private final BeitragMeldungRepository meldungRepository; private final KommentarRepository kommentarRepository; private final UserRepository userRepository; + private final UserService userService; public GruppeController(GruppeRepository gruppeRepository, GruppenmitgliedRepository mitgliedRepository, @@ -42,7 +44,8 @@ public class GruppeController { GruppenbeitragLikeRepository likeRepository, BeitragMeldungRepository meldungRepository, KommentarRepository kommentarRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService) { this.gruppeRepository = gruppeRepository; this.mitgliedRepository = mitgliedRepository; this.anfrageRepository = anfrageRepository; @@ -53,6 +56,7 @@ public class GruppeController { this.meldungRepository = meldungRepository; this.kommentarRepository = kommentarRepository; this.userRepository = userRepository; + this.userService = userService; } record CreateGruppeRequest(String name, String beschreibung, String bild, boolean isPrivate) {} @@ -66,15 +70,15 @@ public class GruppeController { UUID myId = resolveMyId(principal); if (myId == null) return ResponseEntity.status(401).build(); - List result = gruppeRepository.findByNameContainingIgnoreCase(q) - .stream() - .limit(30) + List gruppen = gruppeRepository.findByNameContainingIgnoreCase(q) + .stream().limit(30).toList(); + List gruppeIds = gruppen.stream().map(GruppeEntity::getGruppeId).toList(); + Map latestActivity = buildLatestActivityMap(gruppeIds); + List result = gruppen.stream() .map(g -> toDto(g, myId)) .sorted((a, b) -> { - LocalDateTime la = beitragRepository.findFirstByGruppeIdOrderByCreatedAtDesc(a.gruppeId()) - .map(GruppenbeitragEntity::getCreatedAt).orElse(a.createdAt()); - LocalDateTime lb = beitragRepository.findFirstByGruppeIdOrderByCreatedAtDesc(b.gruppeId()) - .map(GruppenbeitragEntity::getCreatedAt).orElse(b.createdAt()); + LocalDateTime la = latestActivity.getOrDefault(a.gruppeId(), a.createdAt()); + LocalDateTime lb = latestActivity.getOrDefault(b.gruppeId(), b.createdAt()); return lb.compareTo(la); }) .toList(); @@ -88,16 +92,18 @@ public class GruppeController { UUID myId = resolveMyId(principal); if (myId == null) return ResponseEntity.status(401).build(); - List result = mitgliedRepository.findByUserId(myId) + List gruppen = mitgliedRepository.findByUserId(myId) .stream() .map(m -> gruppeRepository.findById(m.getGruppeId()).orElse(null)) .filter(Objects::nonNull) + .toList(); + List gruppeIds = gruppen.stream().map(GruppeEntity::getGruppeId).toList(); + Map latestActivity = buildLatestActivityMap(gruppeIds); + List result = gruppen.stream() .map(g -> toDto(g, myId)) .sorted((a, b) -> { - LocalDateTime la = beitragRepository.findFirstByGruppeIdOrderByCreatedAtDesc(a.gruppeId()) - .map(GruppenbeitragEntity::getCreatedAt).orElse(a.createdAt()); - LocalDateTime lb = beitragRepository.findFirstByGruppeIdOrderByCreatedAtDesc(b.gruppeId()) - .map(GruppenbeitragEntity::getCreatedAt).orElse(b.createdAt()); + LocalDateTime la = latestActivity.getOrDefault(a.gruppeId(), a.createdAt()); + LocalDateTime lb = latestActivity.getOrDefault(b.gruppeId(), b.createdAt()); return lb.compareTo(la); }) .toList(); @@ -465,11 +471,20 @@ public class GruppeController { // ── Helpers ── + private Map buildLatestActivityMap(List gruppeIds) { + if (gruppeIds.isEmpty()) return Map.of(); + Map map = new HashMap<>(); + beitragRepository.findLatestCreatedAtByGruppeIds(gruppeIds).forEach(row -> { + UUID gId = (UUID) row[0]; + LocalDateTime latest = (LocalDateTime) row[1]; + map.put(gId, latest); + }); + return map; + } + private UUID resolveMyId(Principal principal) { if (principal == null) return null; - return userRepository.findByEmail(principal.getName()) - .map(UserEntity::getUserId) - .orElse(null); + return userService.requireUser(principal).getUserId(); } private boolean isAdmin(UUID gruppeId, UUID userId) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppenbeitragController.java b/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppenbeitragController.java index 8434639..fc82ef1 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppenbeitragController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/gruppe/GruppenbeitragController.java @@ -3,9 +3,11 @@ package de.oaa.xxx.gruppe; import de.oaa.xxx.gruppe.dto.*; import de.oaa.xxx.gruppe.entity.*; import de.oaa.xxx.gruppe.repository.*; +import de.oaa.xxx.social.LikeService; import de.oaa.xxx.social.repository.KommentarRepository; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.PageRequest; @@ -31,6 +33,8 @@ public class GruppenbeitragController { private final BeitragMeldungRepository meldungRepository; private final KommentarRepository kommentarRepository; private final UserRepository userRepository; + private final UserService userService; + private final LikeService likeService; public GruppenbeitragController(GruppeRepository gruppeRepository, GruppenmitgliedRepository mitgliedRepository, @@ -40,7 +44,9 @@ public class GruppenbeitragController { GruppenbeitragLikeRepository likeRepository, BeitragMeldungRepository meldungRepository, KommentarRepository kommentarRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService, + LikeService likeService) { this.gruppeRepository = gruppeRepository; this.mitgliedRepository = mitgliedRepository; this.beitragRepository = beitragRepository; @@ -50,6 +56,8 @@ public class GruppenbeitragController { this.meldungRepository = meldungRepository; this.kommentarRepository = kommentarRepository; this.userRepository = userRepository; + this.userService = userService; + this.likeService = likeService; } record CreateBeitragRequest(String beitragTyp, String text, Boolean multiChoice, List optionen, List bilder) {} @@ -175,19 +183,7 @@ public class GruppenbeitragController { if (mitgliedRepository.findFirstByGruppeIdAndUserId(id, myId).isEmpty()) return ResponseEntity.status(403).build(); - var existing = likeRepository.findByBeitragIdAndUserId(postId, myId); - if (existing.isPresent()) { - likeRepository.delete(existing.get()); - LOGGER.debug("User {} hat Like auf Beitrag {} entfernt", myId, postId); - } else { - GruppenbeitragLikeEntity like = new GruppenbeitragLikeEntity(); - like.setLikeId(UUID.randomUUID()); - like.setBeitragId(postId); - like.setUserId(myId); - like.setLikedAt(LocalDateTime.now()); - likeRepository.save(like); - LOGGER.debug("User {} hat Beitrag {} geliked", myId, postId); - } + likeService.toggleGruppenbeitragLike(postId, myId); return ResponseEntity.ok().build(); } @@ -310,9 +306,7 @@ public class GruppenbeitragController { private UUID resolveMyId(Principal principal) { if (principal == null) return null; - return userRepository.findByEmail(principal.getName()) - .map(UserEntity::getUserId) - .orElse(null); + return userService.requireUser(principal).getUserId(); } private void deleteBeitragCascade(GruppenbeitragEntity beitrag) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/gruppe/repository/GruppenbeitragRepository.java b/xxxthegame/src/main/java/de/oaa/xxx/gruppe/repository/GruppenbeitragRepository.java index ae345cd..10b5b81 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/gruppe/repository/GruppenbeitragRepository.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/gruppe/repository/GruppenbeitragRepository.java @@ -4,6 +4,8 @@ import de.oaa.xxx.gruppe.entity.GruppenbeitragEntity; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; @@ -21,6 +23,9 @@ public interface GruppenbeitragRepository extends JpaRepository findByGruppeIdInAndCreatedAtAfterOrderByCreatedAtDesc(List gruppeIds, LocalDateTime since); + @Query("SELECT b.gruppeId, MAX(b.createdAt) FROM GruppenbeitragEntity b WHERE b.gruppeId IN :gruppeIds GROUP BY b.gruppeId") + List findLatestCreatedAtByGruppeIds(@Param("gruppeIds") List gruppeIds); + @Transactional void deleteByGruppeId(UUID gruppeId); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/mail/MailTemplateService.java b/xxxthegame/src/main/java/de/oaa/xxx/mail/MailTemplateService.java index ec681d2..f06fcee 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/mail/MailTemplateService.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/mail/MailTemplateService.java @@ -178,7 +178,7 @@ public class MailTemplateService { """.formatted(baseUrl, targetUrl, colorPrimary) : "
"; - String settingsUrl = baseUrl + "/einstellungen.html#sec-benachrichtigungen"; + String settingsUrl = baseUrl + "/konto/einstellungen.html#sec-benachrichtigungen"; return """ diff --git a/xxxthegame/src/main/java/de/oaa/xxx/meldung/MeldungController.java b/xxxthegame/src/main/java/de/oaa/xxx/meldung/MeldungController.java index 0bc33a8..614e62c 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/meldung/MeldungController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/meldung/MeldungController.java @@ -1,6 +1,6 @@ package de.oaa.xxx.meldung; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -13,11 +13,11 @@ import java.util.UUID; public class MeldungController { private final MeldungRepository meldungRepository; - private final UserRepository userRepository; + private final UserService userService; - public MeldungController(MeldungRepository meldungRepository, UserRepository userRepository) { + public MeldungController(MeldungRepository meldungRepository, UserService userService) { this.meldungRepository = meldungRepository; - this.userRepository = userRepository; + this.userService = userService; } record MeldungRequest(MeldungZielTyp zielTyp, UUID zielId, String grund) {} @@ -25,7 +25,7 @@ public class MeldungController { @PostMapping @Transactional public ResponseEntity melden(@RequestBody MeldungRequest request, Principal principal) { - var user = userRepository.findByEmail(principal.getName()).orElseThrow(); + var user = userService.requireUser(principal); if (meldungRepository.existsByMelderIdAndZielTypAndZielId(user.getUserId(), request.zielTyp(), request.zielId())) { return ResponseEntity.status(409).build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/registration/RegistrationController.java b/xxxthegame/src/main/java/de/oaa/xxx/registration/RegistrationController.java index dc95b9d..d0b3a18 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/registration/RegistrationController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/registration/RegistrationController.java @@ -46,10 +46,19 @@ public class RegistrationController { @PostMapping public ResponseEntity create(@RequestBody Registration registration) { LOGGER.info("POST {}: {}", getClass().getName(), registration); + if (registration.getEmail() == null + || !registration.getEmail().matches("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$")) { + LOGGER.warn("Registrierung abgelehnt – ungültige E-Mail-Adresse"); + return ResponseEntity.status(422).body("EMAIL_FORMAT"); + } + if (registration.getPassword() == null || registration.getPassword().length() < 8) { + LOGGER.warn("Registrierung abgelehnt – Passwort zu kurz (min. 8 Zeichen)"); + return ResponseEntity.status(422).body("PASSWORT_ZU_KURZ"); + } if (registration.getGeburtsdatum() == null || Period.between(registration.getGeburtsdatum(), LocalDate.now()).getYears() < 18) { LOGGER.warn("Registrierung abgelehnt – Mindestalter nicht erreicht"); - return ResponseEntity.status(422).build(); + return ResponseEntity.status(422).body("ALTER"); } // Bereits aktivierte User blockieren if (userRepository.findByEmail(registration.getEmail()).isPresent()) { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/EventController.java b/xxxthegame/src/main/java/de/oaa/xxx/social/EventController.java index c811555..834189d 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/social/EventController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/EventController.java @@ -1,30 +1,28 @@ -package de.oaa.xxx.social; - -import de.oaa.xxx.user.UserRepository; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; - -import java.security.Principal; - -@RestController -@RequestMapping("/events") -public class EventController { - - private final SseService sseService; - private final UserRepository userRepository; - - public EventController(SseService sseService, UserRepository userRepository) { - this.sseService = sseService; - this.userRepository = userRepository; - } - - @GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public SseEmitter stream(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) throw new RuntimeException("Not authenticated"); - return sseService.subscribe(meOpt.get().getUserId()); - } -} +package de.oaa.xxx.social; + +import de.oaa.xxx.user.UserService; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.security.Principal; + +@RestController +@RequestMapping("/events") +public class EventController { + + private final SseService sseService; + private final UserService userService; + + public EventController(SseService sseService, UserService userService) { + this.sseService = sseService; + this.userService = userService; + } + + @GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter stream(Principal principal) { + return sseService.subscribe(userService.requireUser(principal).getUserId()); + } +} diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/KommentarController.java b/xxxthegame/src/main/java/de/oaa/xxx/social/KommentarController.java index 05ee3c9..1e1162f 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/social/KommentarController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/KommentarController.java @@ -2,11 +2,11 @@ package de.oaa.xxx.social; import de.oaa.xxx.social.dto.KommentarDto; import de.oaa.xxx.social.entity.KommentarEntity; -import de.oaa.xxx.social.entity.KommentarLikeEntity; import de.oaa.xxx.social.repository.KommentarLikeRepository; import de.oaa.xxx.social.repository.KommentarRepository; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -26,13 +26,19 @@ public class KommentarController { private final KommentarRepository kommentarRepository; private final KommentarLikeRepository likeRepository; private final UserRepository userRepository; + private final UserService userService; + private final LikeService likeService; public KommentarController(KommentarRepository kommentarRepository, KommentarLikeRepository likeRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService, + LikeService likeService) { this.kommentarRepository = kommentarRepository; this.likeRepository = likeRepository; this.userRepository = userRepository; + this.userService = userService; + this.likeService = likeService; } record CreateKommentarRequest(String targetType, UUID targetId, String text) {} @@ -42,9 +48,7 @@ public class KommentarController { @RequestParam String targetType, @RequestParam UUID targetId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List dtos = kommentarRepository .findByTargetTypeAndTargetIdOrderByCreatedAtAsc(targetType, targetId) @@ -56,9 +60,7 @@ public class KommentarController { @PostMapping public ResponseEntity createKommentar(@RequestBody CreateKommentarRequest request, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (request.text() == null || request.text().isBlank()) return ResponseEntity.badRequest().build(); if (request.text().length() > 500) return ResponseEntity.badRequest().build(); @@ -81,9 +83,7 @@ public class KommentarController { @DeleteMapping("/{kommentarId}") public ResponseEntity deleteKommentar(@PathVariable UUID kommentarId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var kOpt = kommentarRepository.findById(kommentarId); if (kOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -104,25 +104,11 @@ public class KommentarController { @PostMapping("/{kommentarId}/like") public ResponseEntity toggleLike(@PathVariable UUID kommentarId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (kommentarRepository.findById(kommentarId).isEmpty()) return ResponseEntity.notFound().build(); - var existing = likeRepository.findByKommentarIdAndUserId(kommentarId, myId); - if (existing.isPresent()) { - likeRepository.delete(existing.get()); - LOGGER.debug("User {} hat Like auf Kommentar {} entfernt", myId, kommentarId); - } else { - KommentarLikeEntity like = new KommentarLikeEntity(); - like.setLikeId(UUID.randomUUID()); - like.setKommentarId(kommentarId); - like.setUserId(myId); - like.setLikedAt(LocalDateTime.now()); - likeRepository.save(like); - LOGGER.debug("User {} hat Kommentar {} geliked", myId, kommentarId); - } + likeService.toggleKommentarLike(kommentarId, myId); return ResponseEntity.ok().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/LikeService.java b/xxxthegame/src/main/java/de/oaa/xxx/social/LikeService.java new file mode 100644 index 0000000..7f9dfa3 --- /dev/null +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/LikeService.java @@ -0,0 +1,122 @@ +package de.oaa.xxx.social; + +import de.oaa.xxx.feed.entity.FeedPostLikeEntity; +import de.oaa.xxx.feed.repository.FeedPostLikeRepository; +import de.oaa.xxx.gruppe.entity.GruppenbeitragLikeEntity; +import de.oaa.xxx.gruppe.repository.GruppenbeitragLikeRepository; +import de.oaa.xxx.social.entity.KommentarLikeEntity; +import de.oaa.xxx.social.entity.PinnwandLikeEntity; +import de.oaa.xxx.social.entity.ProfileImageLikeEntity; +import de.oaa.xxx.social.repository.KommentarLikeRepository; +import de.oaa.xxx.social.repository.PinnwandLikeRepository; +import de.oaa.xxx.social.repository.ProfileImageLikeRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Service +public class LikeService { + + private static final Logger LOGGER = LoggerFactory.getLogger(LikeService.class); + + private final PinnwandLikeRepository pinnwandLikeRepository; + private final KommentarLikeRepository kommentarLikeRepository; + private final ProfileImageLikeRepository profileImageLikeRepository; + private final FeedPostLikeRepository feedPostLikeRepository; + private final GruppenbeitragLikeRepository gruppenbeitragLikeRepository; + + public LikeService(PinnwandLikeRepository pinnwandLikeRepository, + KommentarLikeRepository kommentarLikeRepository, + ProfileImageLikeRepository profileImageLikeRepository, + FeedPostLikeRepository feedPostLikeRepository, + GruppenbeitragLikeRepository gruppenbeitragLikeRepository) { + this.pinnwandLikeRepository = pinnwandLikeRepository; + this.kommentarLikeRepository = kommentarLikeRepository; + this.profileImageLikeRepository = profileImageLikeRepository; + this.feedPostLikeRepository = feedPostLikeRepository; + this.gruppenbeitragLikeRepository = gruppenbeitragLikeRepository; + } + + public void togglePinnwandLike(UUID eintragId, UUID userId) { + var existing = pinnwandLikeRepository.findByEintragIdAndUserId(eintragId, userId); + if (existing.isPresent()) { + pinnwandLikeRepository.delete(existing.get()); + LOGGER.debug("User {} hat Like auf Pinnwand-Eintrag {} entfernt", userId, eintragId); + } else { + PinnwandLikeEntity like = new PinnwandLikeEntity(); + like.setLikeId(UUID.randomUUID()); + like.setEintragId(eintragId); + like.setUserId(userId); + like.setLikedAt(LocalDateTime.now()); + pinnwandLikeRepository.save(like); + LOGGER.debug("User {} hat Pinnwand-Eintrag {} geliked", userId, eintragId); + } + } + + public void toggleKommentarLike(UUID kommentarId, UUID userId) { + var existing = kommentarLikeRepository.findByKommentarIdAndUserId(kommentarId, userId); + if (existing.isPresent()) { + kommentarLikeRepository.delete(existing.get()); + LOGGER.debug("User {} hat Like auf Kommentar {} entfernt", userId, kommentarId); + } else { + KommentarLikeEntity like = new KommentarLikeEntity(); + like.setLikeId(UUID.randomUUID()); + like.setKommentarId(kommentarId); + like.setUserId(userId); + like.setLikedAt(LocalDateTime.now()); + kommentarLikeRepository.save(like); + LOGGER.debug("User {} hat Kommentar {} geliked", userId, kommentarId); + } + } + + public void toggleProfileImageLike(UUID imageId, UUID userId) { + var existing = profileImageLikeRepository.findByImageIdAndUserId(imageId, userId); + if (existing.isPresent()) { + profileImageLikeRepository.delete(existing.get()); + LOGGER.debug("User {} hat Like auf Profilbild {} entfernt", userId, imageId); + } else { + ProfileImageLikeEntity like = new ProfileImageLikeEntity(); + like.setLikeId(UUID.randomUUID()); + like.setImageId(imageId); + like.setUserId(userId); + like.setLikedAt(LocalDateTime.now()); + profileImageLikeRepository.save(like); + LOGGER.debug("User {} hat Profilbild {} geliked", userId, imageId); + } + } + + public void toggleFeedPostLike(UUID postId, UUID userId) { + var existing = feedPostLikeRepository.findByPostIdAndUserId(postId, userId); + if (existing.isPresent()) { + feedPostLikeRepository.delete(existing.get()); + LOGGER.debug("User {} hat Like auf Feed-Post {} entfernt", userId, postId); + } else { + FeedPostLikeEntity like = new FeedPostLikeEntity(); + like.setLikeId(UUID.randomUUID()); + like.setPostId(postId); + like.setUserId(userId); + like.setLikedAt(LocalDateTime.now()); + feedPostLikeRepository.save(like); + LOGGER.debug("User {} hat Feed-Post {} geliked", userId, postId); + } + } + + public void toggleGruppenbeitragLike(UUID beitragId, UUID userId) { + var existing = gruppenbeitragLikeRepository.findByBeitragIdAndUserId(beitragId, userId); + if (existing.isPresent()) { + gruppenbeitragLikeRepository.delete(existing.get()); + LOGGER.debug("User {} hat Like auf Beitrag {} entfernt", userId, beitragId); + } else { + GruppenbeitragLikeEntity like = new GruppenbeitragLikeEntity(); + like.setLikeId(UUID.randomUUID()); + like.setBeitragId(beitragId); + like.setUserId(userId); + like.setLikedAt(LocalDateTime.now()); + gruppenbeitragLikeRepository.save(like); + LOGGER.debug("User {} hat Beitrag {} geliked", userId, beitragId); + } + } +} diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/NotificationController.java b/xxxthegame/src/main/java/de/oaa/xxx/social/NotificationController.java index 0a3f029..91d5f0b 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/social/NotificationController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/NotificationController.java @@ -2,6 +2,7 @@ package de.oaa.xxx.social; import de.oaa.xxx.social.repository.MessageRepository; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; @@ -17,18 +18,19 @@ public class NotificationController { private final MessageRepository messageRepository; private final UserRepository userRepository; + private final UserService userService; public NotificationController(MessageRepository messageRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService) { this.messageRepository = messageRepository; this.userRepository = userRepository; + this.userService = userService; } @GetMapping public ResponseEntity>> getNotifications(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List> result = messageRepository .findNotificationsForUser(myId, PageRequest.of(0, 10)) @@ -52,9 +54,7 @@ public class NotificationController { @GetMapping("/unread/count") public ResponseEntity getUnreadCount(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); return ResponseEntity.ok( messageRepository.countByReceiverIdAndSystemMessageAndReadAtIsNull(myId, true)); } @@ -62,9 +62,7 @@ public class NotificationController { @Transactional @PostMapping("/{id}/read") public ResponseEntity markOneRead(@PathVariable UUID id, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); messageRepository.markNotificationAsRead(id, myId, LocalDateTime.now()); return ResponseEntity.noContent().build(); } @@ -72,9 +70,7 @@ public class NotificationController { @Transactional @PostMapping("/read-all") public ResponseEntity markAllRead(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); messageRepository.markAllNotificationsAsRead(myId, LocalDateTime.now()); return ResponseEntity.noContent().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/PinnwandController.java b/xxxthegame/src/main/java/de/oaa/xxx/social/PinnwandController.java index 68b0b3d..38732e7 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/social/PinnwandController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/PinnwandController.java @@ -2,12 +2,12 @@ package de.oaa.xxx.social; import de.oaa.xxx.social.dto.PinnwandEintragDto; import de.oaa.xxx.social.entity.PinnwandEintragEntity; -import de.oaa.xxx.social.entity.PinnwandLikeEntity; import de.oaa.xxx.social.repository.KommentarRepository; import de.oaa.xxx.social.repository.PinnwandEintragRepository; import de.oaa.xxx.social.repository.PinnwandLikeRepository; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -28,24 +28,28 @@ public class PinnwandController { private final PinnwandLikeRepository likeRepository; private final KommentarRepository kommentarRepository; private final UserRepository userRepository; + private final UserService userService; + private final LikeService likeService; public PinnwandController(PinnwandEintragRepository eintragRepository, PinnwandLikeRepository likeRepository, KommentarRepository kommentarRepository, - UserRepository userRepository) { + UserRepository userRepository, + UserService userService, + LikeService likeService) { this.eintragRepository = eintragRepository; this.likeRepository = likeRepository; this.kommentarRepository = kommentarRepository; this.userRepository = userRepository; + this.userService = userService; + this.likeService = likeService; } record CreateEintragRequest(UUID profilUserId, String text) {} @GetMapping public ResponseEntity> getEintraege(@RequestParam UUID userId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List dtos = eintragRepository .findByProfilUserIdOrderByCreatedAtDesc(userId) @@ -57,9 +61,7 @@ public class PinnwandController { @PostMapping public ResponseEntity createEintrag(@RequestBody CreateEintragRequest request, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (request.text() == null || request.text().isBlank()) return ResponseEntity.badRequest().build(); if (request.text().length() > 1000) return ResponseEntity.badRequest().build(); @@ -78,9 +80,7 @@ public class PinnwandController { @DeleteMapping("/{eintragId}") public ResponseEntity deleteEintrag(@PathVariable UUID eintragId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var eintragOpt = eintragRepository.findById(eintragId); if (eintragOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -102,25 +102,11 @@ public class PinnwandController { @PostMapping("/{eintragId}/like") public ResponseEntity toggleLike(@PathVariable UUID eintragId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (eintragRepository.findById(eintragId).isEmpty()) return ResponseEntity.notFound().build(); - var existing = likeRepository.findByEintragIdAndUserId(eintragId, myId); - if (existing.isPresent()) { - likeRepository.delete(existing.get()); - LOGGER.debug("User {} hat Like auf Pinnwand-Eintrag {} entfernt", myId, eintragId); - } else { - PinnwandLikeEntity like = new PinnwandLikeEntity(); - like.setLikeId(UUID.randomUUID()); - like.setEintragId(eintragId); - like.setUserId(myId); - like.setLikedAt(LocalDateTime.now()); - likeRepository.save(like); - LOGGER.debug("User {} hat Pinnwand-Eintrag {} geliked", myId, eintragId); - } + likeService.togglePinnwandLike(eintragId, myId); return ResponseEntity.ok().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/ProfileImageController.java b/xxxthegame/src/main/java/de/oaa/xxx/social/ProfileImageController.java index 6f40a4b..833da97 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/social/ProfileImageController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/ProfileImageController.java @@ -2,10 +2,9 @@ package de.oaa.xxx.social; import de.oaa.xxx.social.dto.ProfileImageDto; import de.oaa.xxx.social.entity.ProfileImageEntity; -import de.oaa.xxx.social.entity.ProfileImageLikeEntity; import de.oaa.xxx.social.repository.ProfileImageLikeRepository; import de.oaa.xxx.social.repository.ProfileImageRepository; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -25,23 +24,24 @@ public class ProfileImageController { private final ProfileImageRepository profileImageRepository; private final ProfileImageLikeRepository profileImageLikeRepository; - private final UserRepository userRepository; + private final UserService userService; + private final LikeService likeService; public ProfileImageController(ProfileImageRepository profileImageRepository, ProfileImageLikeRepository profileImageLikeRepository, - UserRepository userRepository) { + UserService userService, + LikeService likeService) { this.profileImageRepository = profileImageRepository; this.profileImageLikeRepository = profileImageLikeRepository; - this.userRepository = userRepository; + this.userService = userService; + this.likeService = likeService; } record UploadRequest(String imageData) {} @PostMapping public ResponseEntity uploadImage(@RequestBody UploadRequest request, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (request.imageData() == null || request.imageData().isBlank()) { return ResponseEntity.badRequest().build(); @@ -63,9 +63,7 @@ public class ProfileImageController { @GetMapping public ResponseEntity> getImages(@RequestParam UUID userId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List images = profileImageRepository.findByUserIdOrderByUploadedAtDesc(userId); List dtos = images.stream().map(img -> toDto(img, myId)).toList(); @@ -74,9 +72,7 @@ public class ProfileImageController { @DeleteMapping("/{imageId}") public ResponseEntity deleteImage(@PathVariable UUID imageId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var imgOpt = profileImageRepository.findById(imageId); if (imgOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -90,25 +86,11 @@ public class ProfileImageController { @PostMapping("/{imageId}/like") public ResponseEntity toggleLike(@PathVariable UUID imageId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (profileImageRepository.findById(imageId).isEmpty()) return ResponseEntity.notFound().build(); - var existing = profileImageLikeRepository.findByImageIdAndUserId(imageId, myId); - if (existing.isPresent()) { - profileImageLikeRepository.delete(existing.get()); - LOGGER.debug("User {} hat Like auf Profilbild {} entfernt", myId, imageId); - } else { - ProfileImageLikeEntity like = new ProfileImageLikeEntity(); - like.setLikeId(UUID.randomUUID()); - like.setImageId(imageId); - like.setUserId(myId); - like.setLikedAt(LocalDateTime.now()); - profileImageLikeRepository.save(like); - LOGGER.debug("User {} hat Profilbild {} geliked", myId, imageId); - } + likeService.toggleProfileImageLike(imageId, myId); return ResponseEntity.ok().build(); } diff --git a/xxxthegame/src/main/java/de/oaa/xxx/social/SocialController.java b/xxxthegame/src/main/java/de/oaa/xxx/social/SocialController.java index a2ab5ef..1d6b12c 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/social/SocialController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/social/SocialController.java @@ -13,6 +13,7 @@ import de.oaa.xxx.social.repository.MessageRepository; import de.oaa.xxx.support.SupportUserService; import de.oaa.xxx.user.UserEntity; import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.PageRequest; @@ -34,17 +35,20 @@ public class SocialController { private final MessageRepository messageRepository; private final SseService sseService; private final SystemMessageService systemMessageService; + private final UserService userService; public SocialController(UserRepository userRepository, FriendshipRepository friendshipRepository, MessageRepository messageRepository, SseService sseService, - SystemMessageService systemMessageService) { + SystemMessageService systemMessageService, + UserService userService) { this.userRepository = userRepository; this.friendshipRepository = friendshipRepository; this.messageRepository = messageRepository; this.sseService = sseService; this.systemMessageService = systemMessageService; + this.userService = userService; } record FriendRequestBody(UUID receiverId) {} @@ -55,9 +59,7 @@ public class SocialController { @GetMapping("/users/{userId}") public ResponseEntity getUserProfile(@PathVariable UUID userId, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); return userRepository.findById(userId) .map(u -> ResponseEntity.ok(toUserProfileWithStatus(u, myId))) .orElse(ResponseEntity.notFound().build()); @@ -67,9 +69,7 @@ public class SocialController { @GetMapping("/users/search") public ResponseEntity> searchUsers(@RequestParam String q, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List results = userRepository.findByNameContainingIgnoreCase(q); List profiles = results.stream() @@ -84,9 +84,8 @@ public class SocialController { @PostMapping("/friends/request") public ResponseEntity sendFriendRequest(@RequestBody FriendRequestBody body, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + var me = userService.requireUser(principal); + UUID myId = me.getUserId(); if (myId.equals(body.receiverId())) { return ResponseEntity.badRequest().build(); @@ -103,10 +102,10 @@ public class SocialController { friendshipRepository.save(f); LOGGER.info("User {} hat Freundschaftsanfrage an User {} gesendet", myId, body.receiverId()); - String senderName = meOpt.get().getName(); + String senderName = me.getName(); systemMessageService.send(myId, body.receiverId(), senderName + " hat dir eine Freundschaftsanfrage gesendet.", - "/benutzer.html?userId=" + myId, + "/community/benutzer.html?userId=" + myId, MessageCause.FRIENDREQUEST); return ResponseEntity.status(201).build(); @@ -114,9 +113,7 @@ public class SocialController { @PostMapping("/friends/accept") public ResponseEntity acceptFriendRequest(@RequestBody FriendshipActionBody body, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var fOpt = friendshipRepository.findById(body.friendshipId()); if (fOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -131,9 +128,7 @@ public class SocialController { @DeleteMapping("/friends/reject") public ResponseEntity rejectOrRemoveFriend(@RequestBody FriendshipActionBody body, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); var fOpt = friendshipRepository.findById(body.friendshipId()); if (fOpt.isEmpty()) return ResponseEntity.notFound().build(); @@ -148,7 +143,7 @@ public class SocialController { @GetMapping("/friends/user/{userId}") public ResponseEntity> getFriendsOfUser(@PathVariable UUID userId, Principal principal) { - if (userRepository.findByEmail(principal.getName()).isEmpty()) return ResponseEntity.status(401).build(); + userService.requireUser(principal); List profiles = friendshipRepository.findFriends(userId, Status.ACCEPTED).stream() .map(f -> { UUID friendId = f.getSenderId().equals(userId) ? f.getReceiverId() : f.getSenderId(); @@ -163,9 +158,7 @@ public class SocialController { @GetMapping("/friends") public ResponseEntity> getFriends(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List dtos = friendshipRepository.findFriends(myId, Status.ACCEPTED).stream() .map(f -> { @@ -185,9 +178,7 @@ public class SocialController { @GetMapping("/friends/pending") public ResponseEntity> getPendingRequests(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List dtos = friendshipRepository.findByReceiverIdAndStatus(myId, Status.PENDING).stream() .map(f -> userRepository.findById(f.getSenderId()) @@ -204,9 +195,7 @@ public class SocialController { @GetMapping("/friends/pending/count") public ResponseEntity getPendingCount(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); return ResponseEntity.ok(friendshipRepository.countByReceiverIdAndStatus(myId, Status.PENDING)); } @@ -214,9 +203,7 @@ public class SocialController { @PostMapping("/messages") public ResponseEntity sendMessage(@RequestBody SendMessageBody body, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (body.text() == null || body.text().isBlank()) return ResponseEntity.badRequest().build(); @@ -240,9 +227,7 @@ public class SocialController { @GetMapping("/messages") public ResponseEntity> getConversations(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); List allMessages = messageRepository.findAllByUser(myId); @@ -274,9 +259,7 @@ public class SocialController { @GetMapping("/messages/unread/count") public ResponseEntity getUnreadCount(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); return ResponseEntity.ok(messageRepository.countUnread(myId)); } @@ -288,9 +271,7 @@ public class SocialController { @RequestParam(required = false) String before, @RequestParam(required = false) String after, Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID myId = meOpt.get().getUserId(); + UUID myId = userService.requireUser(principal).getUserId(); if (after != null) { LocalDateTime afterDt = LocalDateTime.parse(after); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/subscription/SubscriptionController.java b/xxxthegame/src/main/java/de/oaa/xxx/subscription/SubscriptionController.java index 9b120f0..ed6a8de 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/subscription/SubscriptionController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/subscription/SubscriptionController.java @@ -1,6 +1,6 @@ package de.oaa.xxx.subscription; -import de.oaa.xxx.user.UserRepository; +import de.oaa.xxx.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -15,20 +15,18 @@ import java.util.UUID; @RequestMapping("/subscription") public class SubscriptionController { - private final UserRepository userRepository; + private final UserService userService; private final SubscriptionLimitService limitService; - public SubscriptionController(UserRepository userRepository, + public SubscriptionController(UserService userService, SubscriptionLimitService limitService) { - this.userRepository = userRepository; + this.userService = userService; this.limitService = limitService; } @GetMapping("/me") public ResponseEntity> getMySubscription(Principal principal) { - var meOpt = userRepository.findByEmail(principal.getName()); - if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = meOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); Map result = new LinkedHashMap<>(); limitService.getActiveSubscription(userId).ifPresentOrElse(sub -> { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/user/LoginController.java b/xxxthegame/src/main/java/de/oaa/xxx/user/LoginController.java index ebd3bca..eaf2242 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/user/LoginController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/user/LoginController.java @@ -1,5 +1,6 @@ package de.oaa.xxx.user; +import de.oaa.xxx.admin.AdminRepository; import de.oaa.xxx.config.JwtService; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; @@ -30,11 +31,15 @@ public class LoginController { private final UserRepository userRepository; private final JwtService jwtService; private final PasswordEncoder passwordEncoder; + private final AdminRepository adminRepository; + private final UserService userService; - public LoginController(UserRepository userRepository, JwtService jwtService, PasswordEncoder passwordEncoder) { + public LoginController(UserRepository userRepository, JwtService jwtService, PasswordEncoder passwordEncoder, AdminRepository adminRepository, UserService userService) { this.userRepository = userRepository; this.jwtService = jwtService; this.passwordEncoder = passwordEncoder; + this.adminRepository = adminRepository; + this.userService = userService; } @PostMapping @@ -51,7 +56,9 @@ public class LoginController { .maxAge(Duration.ofHours(24)) .build(); response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString()); - return ResponseEntity.ok(user.toUser()); + User u = user.toUser(); + u.setAdmin(adminRepository.existsByUserId(user.getUserId())); + return ResponseEntity.ok(u); } else { return ResponseEntity.noContent().build(); } @@ -62,9 +69,10 @@ public class LoginController { if (principal == null) { return ResponseEntity.status(401).build(); } - return userRepository.findByEmail(principal.getName()) - .map(entity -> ResponseEntity.ok(entity.toUser())) - .orElse(ResponseEntity.status(401).build()); + UserEntity entity = userService.requireUser(principal); + User u = entity.toUser(); + u.setAdmin(adminRepository.existsByUserId(entity.getUserId())); + return ResponseEntity.ok(u); } @GetMapping("/logout") diff --git a/xxxthegame/src/main/java/de/oaa/xxx/user/User.java b/xxxthegame/src/main/java/de/oaa/xxx/user/User.java index 5fced89..ce2eb8e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/user/User.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/user/User.java @@ -15,6 +15,7 @@ public class User { private String name; private String email; private String password; + private boolean admin; private String profilePicture; private LocalDate geburtsdatum; private Integer groesse; diff --git a/xxxthegame/src/main/java/de/oaa/xxx/user/UserController.java b/xxxthegame/src/main/java/de/oaa/xxx/user/UserController.java index 2a5852d..fe36def 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/user/UserController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/user/UserController.java @@ -103,20 +103,17 @@ public class UserController { @PutMapping("/me/picture") public ResponseEntity updateProfilePicture(@RequestBody ProfilePictureRequest request, Principal principal) { - var user = userRepository.findByEmail(principal.getName()); - if (user.isEmpty()) return ResponseEntity.status(401).build(); - user.get().setProfilePicture(request.picture()); - user.get().setProfilePictureHq(request.pictureHq()); - userRepository.save(user.get()); - LOGGER.debug("User {} hat Profilbild aktualisiert", user.get().getUserId()); + var user = userService.requireUser(principal); + user.setProfilePicture(request.picture()); + user.setProfilePictureHq(request.pictureHq()); + userRepository.save(user); + LOGGER.debug("User {} hat Profilbild aktualisiert", user.getUserId()); return ResponseEntity.ok().build(); } @PutMapping("/me/profile") public ResponseEntity updateProfile(@RequestBody ProfileRequest request, Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - var user = userOpt.get(); + var user = userService.requireUser(principal); if (request.beschreibung() != null && request.beschreibung().length() > 600) { return ResponseEntity.badRequest().build(); } @@ -133,9 +130,7 @@ public class UserController { @PutMapping("/me/privacy") public ResponseEntity updatePrivacy(@RequestBody PrivacyRequest request, Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - var user = userOpt.get(); + var user = userService.requireUser(principal); if (request.sichtbarkeitGrunddaten() != null) user.setSichtbarkeitGrunddaten(request.sichtbarkeitGrunddaten()); if (request.sichtbarkeitGalerie() != null) user.setSichtbarkeitGalerie(request.sichtbarkeitGalerie()); if (request.sichtbarkeitFreunde() != null) user.setSichtbarkeitFreunde(request.sichtbarkeitFreunde()); @@ -162,9 +157,7 @@ public class UserController { @GetMapping("/me/notifications") public ResponseEntity> getNotifications(Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); Map byKey = notificationPreferenceRepository.findByUserId(userId) .stream().collect(Collectors.toMap(p -> p.getCause().name(), p -> p)); @@ -183,9 +176,7 @@ public class UserController { @PutMapping("/me/notifications") public ResponseEntity updateNotifications(@RequestBody Map request, Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); for (var entry : request.entrySet()) { MessageCause cause; @@ -213,14 +204,13 @@ public class UserController { @GetMapping("/me/bdsm-defaults") public ResponseEntity> getBdsmDefaults(Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + var currentUser = userService.requireUser(principal); + UUID userId = currentUser.getUserId(); BdsmDefaultsEntity d = bdsmDefaultsRepository.findByUserId(userId) .orElse(new BdsmDefaultsEntity()); Map result = new java.util.LinkedHashMap<>(); - result.put("geschlecht", userOpt.get().getGeschlecht() != null ? userOpt.get().getGeschlecht().name() : null); + result.put("geschlecht", currentUser.getGeschlecht() != null ? currentUser.getGeschlecht().name() : null); result.put("spieltMit", splitOrEmpty(d.getSpieltMit())); result.put("rollen", splitOrEmpty(d.getRollen())); result.put("werkzeuge", splitOrEmpty(d.getWerkzeuge())); @@ -244,9 +234,7 @@ public class UserController { @PutMapping("/me/bdsm-defaults") public ResponseEntity updateBdsmDefaults(@RequestBody BdsmDefaultsRequest request, Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); BdsmDefaultsEntity d = bdsmDefaultsRepository.findByUserId(userId) .orElseGet(() -> { BdsmDefaultsEntity n = new BdsmDefaultsEntity(); n.setUserId(userId); return n; }); @@ -268,9 +256,7 @@ public class UserController { || Period.between(request.geburtsdatum(), LocalDate.now()).getYears() < 18) { return ResponseEntity.status(422).build(); } - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - var user = userOpt.get(); + var user = userService.requireUser(principal); user.setGeburtsdatum(request.geburtsdatum()); userRepository.save(user); LOGGER.info("User {} hat Geburtsdatum aktualisiert", user.getUserId()); @@ -284,20 +270,18 @@ public class UserController { || registrationRepository.findByName(newName).isPresent()) { return ResponseEntity.status(409).build(); } - var user = userRepository.findByEmail(principal.getName()); - if (user.isEmpty()) return ResponseEntity.status(401).build(); - user.get().setName(newName); - userRepository.save(user.get()); - LOGGER.info("User {} hat Namen zu '{}' geändert", user.get().getUserId(), newName); + var user = userService.requireUser(principal); + user.setName(newName); + userRepository.save(user); + LOGGER.info("User {} hat Namen zu '{}' geändert", user.getUserId(), newName); return ResponseEntity.ok().build(); } @DeleteMapping("/me") public ResponseEntity deleteAccount(Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); - String email = userOpt.get().getEmail(); + var currentUser = userService.requireUser(principal); + UUID userId = currentUser.getUserId(); + String email = currentUser.getEmail(); userService.deleteAccount(userId, email); @@ -316,9 +300,8 @@ public class UserController { @GetMapping("/me/ttlock") public ResponseEntity getTtlockUserConfig(Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - TTLockUserConfigEntity cfg = ttLockUserConfigRepository.findById(userOpt.get().getUserId()) + UUID userId = userService.requireUser(principal).getUserId(); + TTLockUserConfigEntity cfg = ttLockUserConfigRepository.findById(userId) .orElse(new TTLockUserConfigEntity()); return ResponseEntity.ok(new TtlockUserConfigDto( cfg.getUsername(), @@ -330,9 +313,7 @@ public class UserController { @PutMapping("/me/ttlock") public ResponseEntity saveTtlockUserConfig(@RequestBody TtlockUserConfigRequest body, Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); TTLockUserConfigEntity cfg = ttLockUserConfigRepository.findById(userId) .orElseGet(() -> { TTLockUserConfigEntity n = new TTLockUserConfigEntity(); n.setUserId(userId); return n; }); boolean credentialsChanged = !java.util.Objects.equals(cfg.getUsername(), body.username()) @@ -352,9 +333,7 @@ public class UserController { @GetMapping("/me/ttlock/test") public ResponseEntity> testTtlockConnection(Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); var userCfg = ttLockUserConfigRepository.findById(userId).orElse(null); if (userCfg == null || userCfg.getUsername() == null || userCfg.getPasswordMd5() == null || userCfg.getLockId() == null) { @@ -394,9 +373,7 @@ public class UserController { @PostMapping("/me/ttlock/open") public ResponseEntity> ttlockOpen(Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); var userCfg = ttLockUserConfigRepository.findById(userId).orElse(null); if (userCfg == null || userCfg.getUsername() == null || userCfg.getPasswordMd5() == null || userCfg.getLockId() == null) { @@ -430,9 +407,7 @@ public class UserController { @DeleteMapping("/me/ttlock/open/{keyboardPwdId}") public ResponseEntity ttlockCloseOpen(@PathVariable int keyboardPwdId, Principal principal) { - var userOpt = userRepository.findByEmail(principal.getName()); - if (userOpt.isEmpty()) return ResponseEntity.status(401).build(); - UUID userId = userOpt.get().getUserId(); + UUID userId = userService.requireUser(principal).getUserId(); var userCfg = ttLockUserConfigRepository.findById(userId).orElse(null); if (userCfg == null || userCfg.getLockId() == null) return ResponseEntity.badRequest().build(); diff --git a/xxxthegame/src/main/java/de/oaa/xxx/user/UserService.java b/xxxthegame/src/main/java/de/oaa/xxx/user/UserService.java index a899509..a8a3af6 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/user/UserService.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/user/UserService.java @@ -27,8 +27,11 @@ import de.oaa.xxx.social.repository.ProfileImageRepository; import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; +import java.security.Principal; import java.util.List; import java.util.UUID; @@ -100,6 +103,15 @@ public class UserService { this.notificationPreferenceRepository = notificationPreferenceRepository; } + /** + * Liefert den UserEntity zum eingeloggten Principal. + * Wirft 401 wenn der User nicht gefunden wird. + */ + public UserEntity requireUser(Principal principal) { + return userRepository.findByEmail(principal.getName()) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.UNAUTHORIZED)); + } + /** * Löscht einen User-Account vollständig inklusive aller abhängigen Daten. * Gibt die gelöschte E-Mail zurück (wird für Cookie-Clearing im Controller benötigt). diff --git a/xxxthegame/src/main/resources/static/admin.html b/xxxthegame/src/main/resources/static/admin/admin.html similarity index 100% rename from xxxthegame/src/main/resources/static/admin.html rename to xxxthegame/src/main/resources/static/admin/admin.html diff --git a/xxxthegame/src/main/resources/static/bdsm.html b/xxxthegame/src/main/resources/static/bdsm.html deleted file mode 100644 index e7f203f..0000000 --- a/xxxthegame/src/main/resources/static/bdsm.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - BDSM Game – xXx Sphere - - - - - diff --git a/xxxthegame/src/main/resources/static/bdsmplayers.html b/xxxthegame/src/main/resources/static/bdsmplayers.html deleted file mode 100644 index e7f203f..0000000 --- a/xxxthegame/src/main/resources/static/bdsmplayers.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - BDSM Game – xXx Sphere - - - - - diff --git a/xxxthegame/src/main/resources/static/bdsmtasks.html b/xxxthegame/src/main/resources/static/bdsmtasks.html deleted file mode 100644 index e7f203f..0000000 --- a/xxxthegame/src/main/resources/static/bdsmtasks.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - BDSM Game – xXx Sphere - - - - - diff --git a/xxxthegame/src/main/resources/static/bdsmtoys.html b/xxxthegame/src/main/resources/static/bdsmtoys.html deleted file mode 100644 index e7f203f..0000000 --- a/xxxthegame/src/main/resources/static/bdsmtoys.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - BDSM Game – xXx Sphere - - - - - diff --git a/xxxthegame/src/main/resources/static/bdsmwarten.html b/xxxthegame/src/main/resources/static/bdsmwarten.html deleted file mode 100644 index e7f203f..0000000 --- a/xxxthegame/src/main/resources/static/bdsmwarten.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - BDSM Game – xXx Sphere - - - - - diff --git a/xxxthegame/src/main/resources/static/abonnements.html b/xxxthegame/src/main/resources/static/community/abonnements.html similarity index 100% rename from xxxthegame/src/main/resources/static/abonnements.html rename to xxxthegame/src/main/resources/static/community/abonnements.html diff --git a/xxxthegame/src/main/resources/static/benachrichtigungen.html b/xxxthegame/src/main/resources/static/community/benachrichtigungen.html similarity index 100% rename from xxxthegame/src/main/resources/static/benachrichtigungen.html rename to xxxthegame/src/main/resources/static/community/benachrichtigungen.html diff --git a/xxxthegame/src/main/resources/static/benutzer.html b/xxxthegame/src/main/resources/static/community/benutzer.html similarity index 96% rename from xxxthegame/src/main/resources/static/benutzer.html rename to xxxthegame/src/main/resources/static/community/benutzer.html index ea27c86..a9e9a57 100644 --- a/xxxthegame/src/main/resources/static/benutzer.html +++ b/xxxthegame/src/main/resources/static/community/benutzer.html @@ -651,14 +651,14 @@ const actions = document.getElementById('profileActions'); const isViewingOwnProfile = myUserId && myUserId === profile.userId; if (isOwnProfile) { - actions.innerHTML = `Profil bearbeiten`; + actions.innerHTML = `Profil bearbeiten`; } else if (isViewingOwnProfile) { // eigenes Profil im Preview-Modus – keine Aktionsbuttons anzeigen actions.innerHTML = ''; } else { let html = ''; if (profile.friendStatus === 'FRIEND') { - html += `✉ Nachricht`; + html += `✉ Nachricht`; } else if (profile.friendStatus === 'PENDING_SENT') { html += ``; } else if (profile.friendStatus === 'PENDING_RECEIVED') { @@ -711,7 +711,7 @@ const banner = document.createElement('div'); banner.style.cssText = 'background:var(--color-secondary);border:1px solid var(--color-primary);border-radius:8px;padding:0.65rem 1rem;margin-bottom:1rem;font-size:0.88rem;display:flex;align-items:center;justify-content:space-between;gap:0.75rem;'; const label = mode === 'FREUND' ? '👥 Vorschau aus Freundessicht' : '👤 Vorschau aus Sicht einer fremden Person'; - banner.innerHTML = `${label}← Einstellungen`; + banner.innerHTML = `${label}← Einstellungen`; document.getElementById('profileView').prepend(banner); } @@ -806,7 +806,7 @@ const pic = f.profilePicture ? `${esc(f.name)}` : `
👤
`; - return `
+ return `
${pic} ${esc(f.name)}
`; @@ -968,7 +968,7 @@ const img = p.picture ? `` : `
👤
`; - return ` + return ` ${img} ${badge ? `${badge}` : ''} `; diff --git a/xxxthegame/src/main/resources/static/einladungen.html b/xxxthegame/src/main/resources/static/community/einladungen.html similarity index 82% rename from xxxthegame/src/main/resources/static/einladungen.html rename to xxxthegame/src/main/resources/static/community/einladungen.html index 370a011..b05df54 100644 --- a/xxxthegame/src/main/resources/static/einladungen.html +++ b/xxxthegame/src/main/resources/static/community/einladungen.html @@ -255,6 +255,30 @@
+ +
+
+
+ +
+
🎲
+
+
+
Vanilla Game – Einladung
+
+
+

+ Du wurdest zu einem Vanilla Game eingeladen. Wie möchtest du mitspielen? +

+
+
+ + + +
+
+
+
@@ -355,7 +379,7 @@ } function buildAvatarHtml(picBase64, type) { - const badge = type === 'keyholder' ? '🔑' : type === 'bdsm' ? '⛓️' : '🔒'; + const badge = type === 'keyholder' ? '🔑' : type === 'bdsm' ? '⛓️' : type === 'vanilla' ? '🎲' : '🔒'; const inner = picBase64 ? `
` : `
👤
`; @@ -375,20 +399,23 @@ // ── Empfangen laden ── async function loadReceivedInvitations() { try { - const [lockeeRes, khRes, bdsmRes] = await Promise.all([ + const [lockeeRes, khRes, bdsmRes, vanillaRes] = await Promise.all([ fetch('/lockee/invitations/mine'), fetch('/keyholder/invitations/mine'), fetch('/bdsm/einladung/pending'), + fetch('/vanilla/einladung/pending'), ]); - const lockeeInvs = lockeeRes.ok ? await lockeeRes.json() : []; - const khInvs = khRes.ok ? await khRes.json() : []; - const bdsmInvs = bdsmRes.ok ? await bdsmRes.json() : []; + const lockeeInvs = lockeeRes.ok ? await lockeeRes.json() : []; + const khInvs = khRes.ok ? await khRes.json() : []; + const bdsmInvs = bdsmRes.ok ? await bdsmRes.json() : []; + const vanillaInvs = vanillaRes.ok ? await vanillaRes.json() : []; - lockeeInvs.forEach(inv => { inv._type = 'lockee'; inv._key = inv.token; inv._otherName = inv.keyholderName; inv._otherPic = inv.keyholderProfilePic; }); - khInvs.forEach(inv => { inv._type = 'keyholder'; inv._key = inv.token; inv._otherName = inv.lockeeName; inv._otherPic = inv.lockeeProfilePic; }); - bdsmInvs.forEach(inv => { inv._type = 'bdsm'; inv._key = inv.einladungId; inv._otherName = inv.inviterName; inv._otherPic = inv.inviterAvatar; }); + lockeeInvs.forEach(inv => { inv._type = 'lockee'; inv._key = inv.token; inv._otherName = inv.keyholderName; inv._otherPic = inv.keyholderProfilePic; }); + khInvs.forEach(inv => { inv._type = 'keyholder'; inv._key = inv.token; inv._otherName = inv.lockeeName; inv._otherPic = inv.lockeeProfilePic; }); + bdsmInvs.forEach(inv => { inv._type = 'bdsm'; inv._key = inv.einladungId; inv._otherName = inv.inviterName; inv._otherPic = inv.inviterAvatar; }); + vanillaInvs.forEach(inv => { inv._type = 'vanilla'; inv._key = inv.einladungId; inv._otherName = inv.inviterName; inv._otherPic = inv.inviterAvatar || ''; }); - recvItems = [...lockeeInvs, ...khInvs, ...bdsmInvs].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + recvItems = [...lockeeInvs, ...khInvs, ...bdsmInvs, ...vanillaInvs].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); recvPage = 0; renderRecvPage(); } catch(e) { console.error(e); } @@ -434,6 +461,13 @@ ✓ Annehmen
`; + } else if (inv._type === 'vanilla') { + typeLabel = 'Vanilla Game'; + line2 = 'Spieleinladung'; + actions = ` +
+ +
`; } else { typeLabel = 'BDSM Game'; line2 = 'Spieleinladung'; @@ -475,17 +509,20 @@ // ── Gesendet laden ── async function loadSentInvitations() { try { - const [lockeeRes, khRes] = await Promise.all([ + const [lockeeRes, khRes, vanillaRes] = await Promise.all([ fetch('/lockee/invitations/sent'), - fetch('/keyholder/invitations/sent') + fetch('/keyholder/invitations/sent'), + fetch('/vanilla/einladung/sent'), ]); - const lockeeInvs = lockeeRes.ok ? await lockeeRes.json() : []; - const khInvs = khRes.ok ? await khRes.json() : []; + const lockeeInvs = lockeeRes.ok ? await lockeeRes.json() : []; + const khInvs = khRes.ok ? await khRes.json() : []; + const vanillaInvs = vanillaRes.ok ? await vanillaRes.json() : []; - lockeeInvs.forEach(inv => { inv._type = 'lockee'; inv._otherName = inv.lockeeName; inv._otherPic = inv.lockeeProfilePic; }); - khInvs.forEach(inv => { inv._type = 'keyholder'; inv._otherName = inv.keyholderName; inv._otherPic = inv.keyholderProfilePic; }); + lockeeInvs.forEach(inv => { inv._type = 'lockee'; inv._key = inv.token; inv._otherName = inv.lockeeName; inv._otherPic = inv.lockeeProfilePic; }); + khInvs.forEach(inv => { inv._type = 'keyholder'; inv._key = inv.token; inv._otherName = inv.keyholderName; inv._otherPic = inv.keyholderProfilePic; }); + vanillaInvs.forEach(inv => { inv._type = 'vanilla'; inv._key = inv.einladungId; inv._otherName = inv.inviteeName; inv._otherPic = ''; }); - sentItems = [...lockeeInvs, ...khInvs].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + sentItems = [...lockeeInvs, ...khInvs, ...vanillaInvs].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); sentPage = 0; renderSentPage(); } catch(e) { console.error(e); } @@ -511,26 +548,31 @@ const av = buildAvatarHtml(inv._otherPic, inv._type); const card = document.createElement('div'); card.className = 'inv-card'; - card.id = 'sentinv-' + inv.token; + card.id = 'sentinv-' + inv._key; - const typeLabel = inv._type === 'lockee' ? 'Lockee-Einladung' : 'Keyholder-Einladung'; - let extra = ''; + let typeLabel, line2sent, extra = ''; if (inv._type === 'lockee') { + typeLabel = 'Lockee-Einladung'; + line2sent = 'Lockee: ' + esc(inv.lockName); extra = inv.detailsVisible ? '  👁 Details sichtbar' : '  🙈 Details verborgen'; + } else if (inv._type === 'vanilla') { + typeLabel = 'Vanilla Game'; + line2sent = 'Spieleinladung'; + } else { + typeLabel = 'Keyholder-Einladung'; + line2sent = 'Keyholder: ' + esc(inv.lockName); } - - const rolePrefix2 = inv._type === 'lockee' ? 'Lockee: ' : 'Keyholder: '; card.innerHTML = ` ${av}
${esc(inv._otherName)}
-
${rolePrefix2}${esc(inv.lockName)}
+
${line2sent}
${typeLabel} · ${fmtDate(inv.createdAt)}${extra}
- +
`; list.appendChild(card); }); @@ -546,8 +588,8 @@ document.getElementById('sentList').scrollIntoView({ behavior: 'smooth', block: 'start' }); } - function removeSentItem(token) { - sentItems = sentItems.filter(i => i.token !== token); + function removeSentItem(key) { + sentItems = sentItems.filter(i => i._key !== key); const total = Math.ceil(sentItems.length / PAGE_SIZE); if (sentPage >= total && sentPage > 0) sentPage = total - 1; renderSentPage(); @@ -595,19 +637,23 @@ } // ── Aktionen: Gesendet ── - async function cancelSentInvitation(token, type, btn) { + async function cancelSentInvitation(key, type, btn) { const title = 'Einladung zurückziehen'; const text = type === 'lockee' ? 'Das Lock wird gelöscht und der Lockee wird benachrichtigt.' + : type === 'vanilla' + ? 'Der eingeladene Spieler wird benachrichtigt.' : 'Der Keyholder wird benachrichtigt.'; if (!await showConfirm(title, text)) return; btn.disabled = true; const url = type === 'lockee' - ? '/lockee/invitations/sent/' + encodeURIComponent(token) - : '/keyholder/invitations/sent/' + encodeURIComponent(token); + ? '/lockee/invitations/sent/' + encodeURIComponent(key) + : type === 'vanilla' + ? '/vanilla/einladung/' + encodeURIComponent(key) + : '/keyholder/invitations/sent/' + encodeURIComponent(key); try { const res = await fetch(url, { method: 'DELETE' }); - if (res.ok || res.status === 204) { removeSentItem(token); } + if (res.ok || res.status === 204) { removeSentItem(key); } else { btn.disabled = false; } } catch(e) { btn.disabled = false; } } @@ -757,7 +803,7 @@ // ── Entsperrcode-Modal ── function showUnlockCodeModal(code, lockId) { document.getElementById('unlockCodeDisplay').textContent = code; - const url = '/activelock.html?lockId=' + lockId; + const url = '/games/chastity/activelock.html?lockId=' + lockId; const btn = document.getElementById('unlockModalBtn'); btn.onclick = () => startCodeScramble(code, url); document.getElementById('unlockModal').classList.add('open'); @@ -838,7 +884,7 @@ closeBdsmInviteDialog(); removeRecvItem(key); if (mode === 'OWN_DEVICE') { - window.location.href = `/neubdsm.html`; + window.location.href = `/games/bdsm/neubdsm.html`; } } catch (_) { errEl.textContent = 'Fehler beim Speichern der Antwort.'; @@ -854,9 +900,59 @@ _bdsmAntworten(null); } + // ── Vanilla-Einladungs-Dialog ── + let activeVanillaEinladungId = null; + + function openVanillaInviteDialog(einladungId, inviterName) { + activeVanillaEinladungId = einladungId; + document.getElementById('vanillaDialogTitle').textContent = inviterName + ' lädt dich ein'; + document.getElementById('vanillaDialogError').style.display = 'none'; + document.getElementById('vanillaInviteDialog').classList.add('open'); + } + + function closeVanillaInviteDialog() { + document.getElementById('vanillaInviteDialog').classList.remove('open'); + activeVanillaEinladungId = null; + } + + async function _vanillaAntworten(mode) { + if (!activeVanillaEinladungId) return; + const accepted = mode !== null; + const errEl = document.getElementById('vanillaDialogError'); + errEl.style.display = 'none'; + try { + const res = await fetch(`/vanilla/einladung/${activeVanillaEinladungId}/antwort`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ accepted, mode }), + }); + if (!res.ok) throw new Error(); + const key = activeVanillaEinladungId; + closeVanillaInviteDialog(); + removeRecvItem(key); + if (mode === 'OWN_DEVICE') { + window.location.href = '/games/vanilla/neuvanilla.html'; + } else if (mode === 'HOST_DEVICE') { + window.location.href = '/userhome.html'; + } + } catch (_) { + errEl.textContent = 'Fehler beim Speichern der Antwort.'; + errEl.style.display = ''; + } + } + + function acceptVanillaOwnDevice() { _vanillaAntworten('OWN_DEVICE'); } + function acceptVanillaHostDevice() { _vanillaAntworten('HOST_DEVICE'); } + + async function declineVanillaFromDialog() { + if (!await showConfirm('Einladung ablehnen', 'Möchtest du diese Vanilla-Game-Einladung wirklich ablehnen?')) return; + _vanillaAntworten(null); + } + // ── Esc schließt Dialog ── document.addEventListener('keydown', e => { if (e.key === 'Escape') { + if (document.getElementById('vanillaInviteDialog').classList.contains('open')) closeVanillaInviteDialog(); if (document.getElementById('bdsmInviteDialog').classList.contains('open')) closeBdsmInviteDialog(); if (document.getElementById('lockeeInviteDialog').classList.contains('open')) closeLockeeInviteDialog(); } diff --git a/xxxthegame/src/main/resources/static/feed.html b/xxxthegame/src/main/resources/static/community/feed.html similarity index 97% rename from xxxthegame/src/main/resources/static/feed.html rename to xxxthegame/src/main/resources/static/community/feed.html index 52ead78..2713d1a 100644 --- a/xxxthegame/src/main/resources/static/feed.html +++ b/xxxthegame/src/main/resources/static/community/feed.html @@ -246,7 +246,7 @@ : '◉'; const privacyLabel = !p.isPublic ? ' 🔒' : ''; const groupBadge = p.postType === 'GROUP' && p.gruppeId - ? `👥 ${esc(p.gruppeName)}` + ? `👥 ${esc(p.gruppeName)}` : ''; const bildHtml = bilderCarousel(p.bilder, p.postId); @@ -276,7 +276,7 @@
${avatarHtml}
- +
${deleteBtn} diff --git a/xxxthegame/src/main/resources/static/freunde.html b/xxxthegame/src/main/resources/static/community/freunde.html similarity index 93% rename from xxxthegame/src/main/resources/static/freunde.html rename to xxxthegame/src/main/resources/static/community/freunde.html index 55199d4..f2bbd71 100644 --- a/xxxthegame/src/main/resources/static/freunde.html +++ b/xxxthegame/src/main/resources/static/community/freunde.html @@ -143,7 +143,7 @@
    - +
    @@ -210,12 +210,12 @@ friends.forEach(f => { list.insertAdjacentHTML('beforeend', `
  • -
  • `); @@ -247,7 +247,7 @@ pending.forEach(f => { list.insertAdjacentHTML('beforeend', `
  • - diff --git a/xxxthegame/src/main/resources/static/gruppe.html b/xxxthegame/src/main/resources/static/community/gruppe.html similarity index 96% rename from xxxthegame/src/main/resources/static/gruppe.html rename to xxxthegame/src/main/resources/static/community/gruppe.html index fc9e36a..7e7fcec 100644 --- a/xxxthegame/src/main/resources/static/gruppe.html +++ b/xxxthegame/src/main/resources/static/community/gruppe.html @@ -339,7 +339,7 @@ // ────────────────────────────────────────────────────────────────────── const params = new URLSearchParams(location.search); const gruppeId = params.get('gruppeId'); - if (!gruppeId) location.href = '/gruppen.html'; + if (!gruppeId) location.href = '/community/gruppen.html'; let myId = null; let myRole = null; @@ -405,7 +405,7 @@ } else if (gruppeData.myRequestStatus === 'AUSSTEHEND') { ha.innerHTML = ``; } else { - ha.innerHTML = `← Zurück`; + ha.innerHTML = `← Zurück`; } // Admin tab @@ -495,7 +495,7 @@
    ${av}
    @@ -686,7 +686,7 @@ list.insertAdjacentHTML('beforeend', `
  • ${av}
    - ${esc(m.userName)} + ${esc(m.userName)} ${roleBadge} ${actions}
  • `); @@ -728,7 +728,7 @@ async function confirmLeave() { const res = await fetch('/gruppen/' + gruppeId + '/leave', { method:'DELETE' }); if (res.ok || res.status === 204) { - location.href = '/gruppen.html'; + location.href = '/community/gruppen.html'; } } @@ -893,7 +893,7 @@ async function deleteGruppe() { const res = await fetch('/gruppen/' + gruppeId, { method:'DELETE' }); if (res.ok || res.status === 204) { - location.href = '/gruppen.html'; + location.href = '/community/gruppen.html'; } else { showModal('Fehler', 'Fehler beim Löschen der Gruppe.', [{ label: 'OK' }]); } @@ -976,7 +976,7 @@
    ${av}
    - +
    diff --git a/xxxthegame/src/main/resources/static/gruppen.html b/xxxthegame/src/main/resources/static/community/gruppen.html similarity index 97% rename from xxxthegame/src/main/resources/static/gruppen.html rename to xxxthegame/src/main/resources/static/community/gruppen.html index 6025fb5..cf30f28 100644 --- a/xxxthegame/src/main/resources/static/gruppen.html +++ b/xxxthegame/src/main/resources/static/community/gruppen.html @@ -176,7 +176,7 @@ } } return ` -
    +
    ${img}
    ${esc(g.name)}${privBadge} ${roleBadge}
    @@ -326,7 +326,7 @@ if (res.ok || res.status === 201) { const g = await res.json(); closeCreateDialog(); - window.location.href = '/gruppe.html?gruppeId=' + g.gruppeId; + window.location.href = '/community/gruppe.html?gruppeId=' + g.gruppeId; } else { showCreateError('Fehler beim Erstellen der Gruppe.'); } diff --git a/xxxthegame/src/main/resources/static/nachrichten.html b/xxxthegame/src/main/resources/static/community/nachrichten.html similarity index 96% rename from xxxthegame/src/main/resources/static/nachrichten.html rename to xxxthegame/src/main/resources/static/community/nachrichten.html index 33d711a..4f5f054 100644 --- a/xxxthegame/src/main/resources/static/nachrichten.html +++ b/xxxthegame/src/main/resources/static/community/nachrichten.html @@ -359,7 +359,7 @@ const list = document.getElementById('convList'); list.innerHTML = ''; if (convs.length === 0) { - list.innerHTML = '
  • Noch keine Nachrichten. Personen suchen
  • '; + list.innerHTML = '
  • Noch keine Nachrichten. Personen suchen
  • '; return; } convs.forEach(c => { @@ -403,7 +403,7 @@ partnerName = convItem ? convItem.querySelector('.conv-name').textContent : '…'; } document.getElementById('threadPartnerName').innerHTML = - `${esc(partnerName)}`; + `${esc(partnerName)}`; const avatarEl = document.getElementById('threadPartnerAvatar'); if (partnerPic) { diff --git a/xxxthegame/src/main/resources/static/personen-suchen.html b/xxxthegame/src/main/resources/static/community/personen-suchen.html similarity index 91% rename from xxxthegame/src/main/resources/static/personen-suchen.html rename to xxxthegame/src/main/resources/static/community/personen-suchen.html index f4d6d99..e18b89e 100644 --- a/xxxthegame/src/main/resources/static/personen-suchen.html +++ b/xxxthegame/src/main/resources/static/community/personen-suchen.html @@ -127,7 +127,7 @@ : '◉'; list.insertAdjacentHTML('beforeend', `
  • - @@ -138,7 +138,7 @@ function buildActions(u) { if (u.friendStatus === 'FRIEND') { - return `✉ Nachricht`; + return `✉ Nachricht`; } if (u.friendStatus === 'PENDING_SENT') { return ``; @@ -184,7 +184,7 @@ const item = btn.closest('.user-item'); if (item) { item.querySelector('.user-actions').innerHTML = - `✉ Nachricht`; + `✉ Nachricht`; } } else { btn.disabled = false; diff --git a/xxxthegame/src/main/resources/static/aufgaben.html b/xxxthegame/src/main/resources/static/games/bdsm/aufgaben.html similarity index 100% rename from xxxthegame/src/main/resources/static/aufgaben.html rename to xxxthegame/src/main/resources/static/games/bdsm/aufgaben.html diff --git a/xxxthegame/src/main/resources/static/bdsm-einladung.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsm-einladung.html similarity index 98% rename from xxxthegame/src/main/resources/static/bdsm-einladung.html rename to xxxthegame/src/main/resources/static/games/bdsm/bdsm-einladung.html index ad12cda..f181f06 100644 --- a/xxxthegame/src/main/resources/static/bdsm-einladung.html +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsm-einladung.html @@ -98,7 +98,7 @@ document.getElementById('sub').textContent = 'Du hast die Einladung abgelehnt.'; document.getElementById('actions').innerHTML = ''; } else if (mode === 'OWN_DEVICE') { - window.location.replace(`/neubdsm.html`); + window.location.replace(`/games/bdsm/neubdsm.html`); } else { zeigeBestaetigt(); } diff --git a/xxxthegame/src/main/resources/static/games/bdsm/bdsm.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsm.html new file mode 100644 index 0000000..72717e6 --- /dev/null +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsm.html @@ -0,0 +1,11 @@ + + + + + + BDSM Game – xXx Sphere + + + + + diff --git a/xxxthegame/src/main/resources/static/bdsmingame.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsmingame.html similarity index 97% rename from xxxthegame/src/main/resources/static/bdsmingame.html rename to xxxthegame/src/main/resources/static/games/bdsm/bdsmingame.html index 8bcfb1f..be6866e 100644 --- a/xxxthegame/src/main/resources/static/bdsmingame.html +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsmingame.html @@ -338,7 +338,7 @@ const setup = JSON.parse(sessionStorage.getItem('bdsm-session-setup') || 'null'); const toys = JSON.parse(sessionStorage.getItem('bdsm-session-toys') || '[]'); const sessionId = sessionStorage.getItem('bdsm-session-id'); - if (!sessionId) window.location.replace('/neubdsm.html'); + if (!sessionId) window.location.replace('/games/bdsm/neubdsm.html'); // Multi-Device: bin ich Gast? const isGuest = sessionStorage.getItem('bdsm-is-guest') === 'true'; @@ -425,7 +425,7 @@ try { const res = await fetch(`/bdsm/${sessionId}/aufgaben/next`); if (res.status === 204) { zeigeFinaleDialog(); return; } - if (res.status === 400) { window.location.replace('/neubdsm.html'); return; } + if (res.status === 400) { window.location.replace('/games/bdsm/neubdsm.html'); return; } if (!res.ok) throw new Error(`HTTP ${res.status}`); currentTask = await res.json(); await saveAktiveAufgabe(currentTask, null); @@ -1019,7 +1019,7 @@ clearInterval(scrambleInt); clearInterval(countdownInt); versteckeModal(); - window.location.href = '/keyholder.html'; + window.location.href = '/games/chastity/keyholder.html'; } hintEl.style.display = 'none'; diff --git a/xxxthegame/src/main/resources/static/games/bdsm/bdsmplayers.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsmplayers.html new file mode 100644 index 0000000..72717e6 --- /dev/null +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsmplayers.html @@ -0,0 +1,11 @@ + + + + + + BDSM Game – xXx Sphere + + + + + diff --git a/xxxthegame/src/main/resources/static/games/bdsm/bdsmtasks.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsmtasks.html new file mode 100644 index 0000000..72717e6 --- /dev/null +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsmtasks.html @@ -0,0 +1,11 @@ + + + + + + BDSM Game – xXx Sphere + + + + + diff --git a/xxxthegame/src/main/resources/static/games/bdsm/bdsmtoys.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsmtoys.html new file mode 100644 index 0000000..72717e6 --- /dev/null +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsmtoys.html @@ -0,0 +1,11 @@ + + + + + + BDSM Game – xXx Sphere + + + + + diff --git a/xxxthegame/src/main/resources/static/games/bdsm/bdsmwarten.html b/xxxthegame/src/main/resources/static/games/bdsm/bdsmwarten.html new file mode 100644 index 0000000..72717e6 --- /dev/null +++ b/xxxthegame/src/main/resources/static/games/bdsm/bdsmwarten.html @@ -0,0 +1,11 @@ + + + + + + BDSM Game – xXx Sphere + + + + + diff --git a/xxxthegame/src/main/resources/static/infobdsm.html b/xxxthegame/src/main/resources/static/games/bdsm/infobdsm.html similarity index 100% rename from xxxthegame/src/main/resources/static/infobdsm.html rename to xxxthegame/src/main/resources/static/games/bdsm/infobdsm.html diff --git a/xxxthegame/src/main/resources/static/neubdsm.html b/xxxthegame/src/main/resources/static/games/bdsm/neubdsm.html similarity index 99% rename from xxxthegame/src/main/resources/static/neubdsm.html rename to xxxthegame/src/main/resources/static/games/bdsm/neubdsm.html index 0351bb5..c30fed5 100644 --- a/xxxthegame/src/main/resources/static/neubdsm.html +++ b/xxxthegame/src/main/resources/static/games/bdsm/neubdsm.html @@ -1180,7 +1180,7 @@ sessionStorage.setItem('bdsm-session-id', sessionId); fetch('/bdsm/setup-draft', { method: 'DELETE' }).catch(() => {}); - window.location.href = '/bdsmingame.html'; + window.location.href = '/games/bdsm/bdsmingame.html'; } catch (e) { showMessage(e.message, 'error'); btn.disabled = false; } } @@ -1234,7 +1234,7 @@ sessionStorage.setItem('bdsm-guest-name', mData.name); sessionStorage.setItem('bdsm-session-id', data.sessionId); sessionStorage.setItem('bdsm-is-guest', 'true'); - stopGuestPoll(); window.location.replace('/bdsmingame.html'); + stopGuestPoll(); window.location.replace('/games/bdsm/bdsmingame.html'); } } catch (_) {} } @@ -1259,7 +1259,7 @@ function sessionFortfahren(sid) { BDSM_STORAGE_KEYS.forEach(k => sessionStorage.removeItem(k)); - sessionStorage.setItem('bdsm-session-id', sid); window.location.href = '/bdsmingame.html'; + sessionStorage.setItem('bdsm-session-id', sid); window.location.href = '/games/bdsm/bdsmingame.html'; } function sessionBeendenFragen(sid) { @@ -1306,7 +1306,7 @@ try { const mRes = await fetch(`/bdsm/${einladung.sessionId}/mitspieler/me`); if (mRes.ok) { const mData = await mRes.json(); sessionStorage.setItem('bdsm-guest-mitspieler-id', mData.mitspielerId); sessionStorage.setItem('bdsm-guest-name', mData.name); } } catch (_) {} sessionStorage.setItem('bdsm-session-id', einladung.sessionId); sessionStorage.setItem('bdsm-is-guest', 'true'); - window.location.replace('/bdsmingame.html'); return; + window.location.replace('/games/bdsm/bdsmingame.html'); return; } await initGuestMode(einladung, user); return; } diff --git a/xxxthegame/src/main/resources/static/activelock.html b/xxxthegame/src/main/resources/static/games/chastity/activelock.html similarity index 97% rename from xxxthegame/src/main/resources/static/activelock.html rename to xxxthegame/src/main/resources/static/games/chastity/activelock.html index 331f94e..9f15bc1 100644 --- a/xxxthegame/src/main/resources/static/activelock.html +++ b/xxxthegame/src/main/resources/static/games/chastity/activelock.html @@ -814,7 +814,7 @@ // Prüfen, ob es ein TimeLock ist const tlRes = await fetch('/keyholder/timelock/' + lockId); if (tlRes.ok) { - window.location.replace('/activetimelock.html?lockId=' + lockId); + window.location.replace('/games/chastity/activetimelock.html?lockId=' + lockId); return; } document.getElementById('lockContent').textContent = 'Lock nicht gefunden.'; @@ -1078,7 +1078,7 @@ if (!lock.hasKeyholder || !lock.keyholderName) { bar.style.display = 'none'; return; } bar.style.display = 'flex'; name.textContent = lock.keyholderName; - name.href = '/benutzer.html?userId=' + lock.keyholderUserId; + name.href = '/community/benutzer.html?userId=' + lock.keyholderUserId; if (lock.keyholderProfilePic) { avatar.innerHTML = ``; } else { diff --git a/xxxthegame/src/main/resources/static/activetimelock.html b/xxxthegame/src/main/resources/static/games/chastity/activetimelock.html similarity index 99% rename from xxxthegame/src/main/resources/static/activetimelock.html rename to xxxthegame/src/main/resources/static/games/chastity/activetimelock.html index c2b316d..2fd94af 100644 --- a/xxxthegame/src/main/resources/static/activetimelock.html +++ b/xxxthegame/src/main/resources/static/games/chastity/activetimelock.html @@ -552,7 +552,7 @@ if (!lock.hasKeyholder || !lock.keyholderName) { bar.style.display = 'none'; return; } bar.style.display = 'flex'; name.textContent = lock.keyholderName; - name.href = '/benutzer.html?userId=' + lock.keyholderUserId; + name.href = '/community/benutzer.html?userId=' + lock.keyholderUserId; if (lock.keyholderProfilePic) { avatar.innerHTML = ``; } else { diff --git a/xxxthegame/src/main/resources/static/communityvotes.html b/xxxthegame/src/main/resources/static/games/chastity/communityvotes.html similarity index 100% rename from xxxthegame/src/main/resources/static/communityvotes.html rename to xxxthegame/src/main/resources/static/games/chastity/communityvotes.html diff --git a/xxxthegame/src/main/resources/static/entdecken-vorlagen.html b/xxxthegame/src/main/resources/static/games/chastity/entdecken-vorlagen.html similarity index 100% rename from xxxthegame/src/main/resources/static/entdecken-vorlagen.html rename to xxxthegame/src/main/resources/static/games/chastity/entdecken-vorlagen.html diff --git a/xxxthegame/src/main/resources/static/entdecken.html b/xxxthegame/src/main/resources/static/games/chastity/entdecken.html similarity index 100% rename from xxxthegame/src/main/resources/static/entdecken.html rename to xxxthegame/src/main/resources/static/games/chastity/entdecken.html diff --git a/xxxthegame/src/main/resources/static/infochastity.html b/xxxthegame/src/main/resources/static/games/chastity/infochastity.html similarity index 100% rename from xxxthegame/src/main/resources/static/infochastity.html rename to xxxthegame/src/main/resources/static/games/chastity/infochastity.html diff --git a/xxxthegame/src/main/resources/static/joinlock.html b/xxxthegame/src/main/resources/static/games/chastity/joinlock.html similarity index 95% rename from xxxthegame/src/main/resources/static/joinlock.html rename to xxxthegame/src/main/resources/static/games/chastity/joinlock.html index 8b8cda6..6f67629 100644 --- a/xxxthegame/src/main/resources/static/joinlock.html +++ b/xxxthegame/src/main/resources/static/games/chastity/joinlock.html @@ -104,7 +104,7 @@
    ⚠️

    Einladung nicht gefunden

    Diese Einladung existiert nicht oder wurde bereits bearbeitet.

    - Zu meinen Einladungen + Zu meinen Einladungen
  • @@ -117,7 +117,7 @@

    Einladung abgelehnt

    Du hast die Einladung abgelehnt. Der Keyholder wurde benachrichtigt.

    - Zu meinen Einladungen + Zu meinen Einladungen
    `; return; } @@ -672,7 +672,7 @@ function showActiveLockError() { const el = document.getElementById('errorMsg'); el.innerHTML = 'Du befindest dich bereits in einem aktiven Lock. ' - + 'Zum aktiven Lock'; + + 'Zum aktiven Lock'; el.style.display = ''; el.scrollIntoView({ behavior: 'smooth', block: 'center' }); } @@ -839,11 +839,11 @@ const data = await res.json(); if (data.lockeeInvitationSent) { - window.location.href = '/einladungen.html?tab=gesendet'; + window.location.href = '/community/einladungen.html?tab=gesendet'; } else if (!data.unlockCode) { // Trust: kein Code, direkt weiter const isTimeLock = selectedTemplate && selectedTemplate._type === 'timelock'; - window.location.href = (isTimeLock ? '/activetimelock.html' : '/activelock.html') + window.location.href = (isTimeLock ? '/games/chastity/activetimelock.html' : '/games/chastity/activelock.html') + '?lockId=' + data.lockId + (data.keyholderPending ? '&keyholderPending=1' : ''); } else if (selectedLockControl === 'TTLOCK') { showTtlockStartModal(data.unlockCode, data.lockId, data.keyholderPending); @@ -856,7 +856,7 @@ function showTtlockStartModal(code, lockId, keyholderPending) { const isTimeLock = selectedTemplate && selectedTemplate._type === 'timelock'; const lockType = isTimeLock ? 'timelock' : 'cardlock'; - const targetUrl = (isTimeLock ? '/activetimelock.html' : '/activelock.html') + const targetUrl = (isTimeLock ? '/games/chastity/activetimelock.html' : '/games/chastity/activelock.html') + '?lockId=' + lockId + (keyholderPending ? '&keyholderPending=1' : ''); document.getElementById('unlockCodeDisplay').textContent = code; @@ -885,7 +885,7 @@ document.getElementById('unlockCodeDisplay').textContent = code; if (keyholderPending) document.getElementById('unlockKeyholderHint').style.display = ''; const isTimeLock = selectedTemplate && selectedTemplate._type === 'timelock'; - const targetPage = isTimeLock ? '/activetimelock.html' : '/activelock.html'; + const targetPage = isTimeLock ? '/games/chastity/activetimelock.html' : '/games/chastity/activelock.html'; const url = targetPage + '?lockId=' + lockId + (keyholderPending ? '&keyholderPending=1' : ''); document.getElementById('unlockModalBtn').onclick = () => startCodeScramble(code, url); document.getElementById('unlockModal').classList.add('open'); diff --git a/xxxthegame/src/main/resources/static/sessionchastity.html b/xxxthegame/src/main/resources/static/games/chastity/sessionchastity.html similarity index 64% rename from xxxthegame/src/main/resources/static/sessionchastity.html rename to xxxthegame/src/main/resources/static/games/chastity/sessionchastity.html index 333d612..d726745 100644 --- a/xxxthegame/src/main/resources/static/sessionchastity.html +++ b/xxxthegame/src/main/resources/static/games/chastity/sessionchastity.html @@ -3,7 +3,7 @@ - + diff --git a/xxxthegame/src/main/resources/static/toys.html b/xxxthegame/src/main/resources/static/games/chastity/toys.html similarity index 100% rename from xxxthegame/src/main/resources/static/toys.html rename to xxxthegame/src/main/resources/static/games/chastity/toys.html diff --git a/xxxthegame/src/main/resources/static/unlock-history.html b/xxxthegame/src/main/resources/static/games/chastity/unlock-history.html similarity index 100% rename from xxxthegame/src/main/resources/static/unlock-history.html rename to xxxthegame/src/main/resources/static/games/chastity/unlock-history.html diff --git a/xxxthegame/src/main/resources/static/infovanilla.html b/xxxthegame/src/main/resources/static/games/vanilla/infovanilla.html similarity index 100% rename from xxxthegame/src/main/resources/static/infovanilla.html rename to xxxthegame/src/main/resources/static/games/vanilla/infovanilla.html diff --git a/xxxthegame/src/main/resources/static/neuvanilla.html b/xxxthegame/src/main/resources/static/games/vanilla/neuvanilla.html similarity index 91% rename from xxxthegame/src/main/resources/static/neuvanilla.html rename to xxxthegame/src/main/resources/static/games/vanilla/neuvanilla.html index 36aa24d..d5b676e 100644 --- a/xxxthegame/src/main/resources/static/neuvanilla.html +++ b/xxxthegame/src/main/resources/static/games/vanilla/neuvanilla.html @@ -175,21 +175,14 @@
    Mittel
    -
    -
    - - -
    - -
    +
    +
    Mitspieler
    - +
    - +
    @@ -70,7 +70,7 @@
    - +
    @@ -79,7 +79,7 @@
    - +
    @@ -96,10 +96,10 @@