Fehlerbehebungen Vanilla Game, Refactoring der Seitennamen

This commit is contained in:
2026-03-29 22:59:12 +02:00
parent e262a1b46b
commit 9d6506b54c
138 changed files with 3449 additions and 3320 deletions

View File

@@ -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)"
]
}
}

Submodule .claude/worktrees/agent-a211ce07 added at e262a1b46b

View File

@@ -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

View File

@@ -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

View File

@@ -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",

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<typeInfoHistroy>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.aufgaben{DefaultFiller.java[DefaultFiller" modifiers="1" timestamp="1772437686926"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.aufgaben.controller{FillerController.java[FillerController" modifiers="1" timestamp="1772385528555"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.user{UserRepository.java[UserRepository" modifiers="513" timestamp="1774016609131"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.ttlock{TTLockUserConfigEntity.java[TTLockUserConfigEntity" modifiers="1" timestamp="1774425822887"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.keyholder{KeyholderNotificationEntity.java[KeyholderNotificationEntity" modifiers="1" timestamp="1774386563354"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.cardlock{CardLockEntity.java[CardLockEntity" modifiers="1" timestamp="1774171624571"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.user{UserController.java[UserController" modifiers="1" timestamp="1774551025161"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.ttlock{TTLockService.java[TTLockService" modifiers="1" timestamp="1774375173709"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.timelock{TimeLockController.java[TimeLockController" modifiers="1" timestamp="1774558039992"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.common{BaseLockService.java[BaseLockService" modifiers="1025" timestamp="1774551269600"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.ttlock{TTLockCallback.java[TTLockCallback" modifiers="1" timestamp="1774387007874"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.lockcontroll{TTLockControl.java[TTLockControl" modifiers="1" timestamp="1774383035013"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.cardlock{CardLockController.java[CardLockController" modifiers="1" timestamp="1774550581083"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.common{BaseLockEntity.java[BaseLockEntity" modifiers="1" timestamp="1774476260239"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.cardlock{CardLockService.java[CardLockService" modifiers="1" timestamp="1774551407143"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.timelock{TimeLockService.java[TimeLockService" modifiers="1" timestamp="1774551447849"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.aufgaben.controller{AboController.java[AboController" modifiers="1" timestamp="1773400404000"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.user{UserRepository.java[UserRepository" modifiers="513" timestamp="1774814915722"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.ttlock{TTLockUserConfigEntity.java[TTLockUserConfigEntity" modifiers="1" timestamp="1774814915717"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.keyholder{KeyholderNotificationEntity.java[KeyholderNotificationEntity" modifiers="1" timestamp="1774814915717"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.cardlock{CardLockEntity.java[CardLockEntity" modifiers="1" timestamp="1774814915718"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.user{UserController.java[UserController" modifiers="1" timestamp="1774814915722"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.ttlock{TTLockService.java[TTLockService" modifiers="1" timestamp="1774814915716"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.timelock{TimeLockController.java[TimeLockController" modifiers="1" timestamp="1774814915715"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.common{BaseLockService.java[BaseLockService" modifiers="1025" timestamp="1774814915716"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.ttlock{TTLockCallback.java[TTLockCallback" modifiers="1" timestamp="1774814915716"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.lockcontroll{TTLockControl.java[TTLockControl" modifiers="1" timestamp="1774814915717"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.cardlock{CardLockController.java[CardLockController" modifiers="1" timestamp="1774814915718"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.common{BaseLockEntity.java[BaseLockEntity" modifiers="1" timestamp="1774814915716"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.cardlock{CardLockService.java[CardLockService" modifiers="1" timestamp="1774814915718"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.chastity.timelock{TimeLockService.java[TimeLockService" modifiers="1" timestamp="1774814915716"/>
<typeInfo handle="=xxxthegame/src\/main\/java=/gradle_scope=/main=/=/gradle_used_by_scope=/main,test=/&lt;de.oaa.xxx.games.common.aufgaben{Aufgabe.java[Aufgabe" modifiers="1" timestamp="1774814915721"/>
</typeInfoHistroy>

View File

@@ -32,4 +32,6 @@
<fullyQualifiedTypeName name="de.oaa.xxx.games.chastity.cardlock.CumCard"/>
<fullyQualifiedTypeName name="de.oaa.xxx.games.chastity.cardlock.CumInCageCard"/>
<fullyQualifiedTypeName name="de.oaa.xxx.games.chastity.unlock.TempOpeningReason"/>
<fullyQualifiedTypeName name="de.oaa.xxx.games.vanilla.VanillaMitspieler"/>
<fullyQualifiedTypeName name="de.oaa.xxx.games.common.aufgaben.CommonMitspieler"/>
</qualifiedTypeNameHistroy>

View File

@@ -65,6 +65,7 @@
<item key="updateTextualMatches" value="false"/>
<item key="updateQualifiedNames" value="false"/>
<item key="patterns" value="*"/>
<item key="renameSubpackages" value="false"/>
</section>
<section name="org.eclipse.jdt.internal.ui.typehierarchy.QuickHierarchy">
<item key="org.eclipse.jdt.internal.ui.typehierarchy.HierarchyInformationControlDIALOG_WIDTH" value="400"/>
@@ -76,4 +77,11 @@
<item key="width" value="600"/>
<item key="height" value="400"/>
</section>
<section name="NewInterfaceCreationWizard.dialogBounds">
<item key="DIALOG_X_ORIGIN" value="974"/>
<item key="DIALOG_Y_ORIGIN" value="312"/>
<item key="DIALOG_WIDTH" value="613"/>
<item key="DIALOG_HEIGHT" value="559"/>
<item key="DIALOG_FONT_NAME" value="1|Ubuntu|10.0|0|GTK|1|"/>
</section>
</section>

View File

@@ -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.

View File

@@ -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

Binary file not shown.

View File

@@ -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<AdminDto> 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<Void> 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(

View File

@@ -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()

View File

@@ -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();

View File

@@ -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<FeedItemDto> 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) {

View File

@@ -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;

View File

@@ -19,7 +19,7 @@ import de.oaa.xxx.games.bdsm.sperre.SperrenVerlaengernCallback;
public class BdsmGameDurchfuehren {
private final AufgabenList aufgabenList;
private final List<Mitspieler> mitspieler = new ArrayList<>();
private final List<BdsmMitspieler> mitspieler = new ArrayList<>();
private final List<AktiveSperre> 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<Aufgabe> 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<Strafe> 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<Sperre> 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<Mitspieler> list = mitspieler.stream()
private BdsmMitspieler findeMitspielerMitRolle(RolleEnum rolle) {
List<BdsmMitspieler> 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<Mitspieler> list = mitspieler.stream()
List<BdsmMitspieler> list = mitspieler.stream()
.filter(m -> m != gegenspieler)
.filter(m -> m.isPassenderSpielpartner(gegenspieler))
.filter(m -> m.getRollen().contains(rolle))

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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<AufgabenGruppe> 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<Void> 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<Void> 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);
}
}

View File

@@ -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();
}

View File

@@ -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<AufgabenGruppeList> getAll(@RequestParam(required = false) String search) {
UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public ResponseEntity<AufgabenGruppeList> 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<AufgabenGruppeEntity> page) {

View File

@@ -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<Integer> 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<List<Map<String, Object>>> getPending(Principal principal) {
UUID userId = currentUserId(principal);

View File

@@ -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<Void> 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<Void> 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<Void> 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<Void> addMitspieler(@RequestBody Mitspieler mitspieler, @PathVariable UUID sessionId) {
public ResponseEntity<Void> 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<Map<String, Object>> 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()

View File

@@ -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<Map<String, Object>> 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<Void> 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<Void> 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();
}

View File

@@ -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<FavoritList> all() {
UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public ResponseEntity<FavoritList> all(Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
List<FavoritEntity> 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<Void> create(@RequestBody Favorit favorit) {
UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public ResponseEntity<Void> 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<Void> delete(@RequestBody Favorit favorit) {
public ResponseEntity<Void> 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();

View File

@@ -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<ToyEntity> 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<List<Toy>> 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<ToyEntity> own = toyRepository.findByUserId(user.getUserId(), PageRequest.of(0, 500, Sort.by("name"))).getContent();
List<ToyEntity> 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<Void> 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<Void> 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();

View File

@@ -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<Mitspieler> mitspielerList) {
public AktiveSperre toSperre(List<BdsmMitspieler> 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<Mitspieler> mitspielerList, UUID id) {
Optional<Mitspieler> first = mitspielerList.stream().filter(m -> m.getId().equals(id)).findFirst();
private BdsmMitspieler getMitspielerFromList(List<BdsmMitspieler> mitspielerList, UUID id) {
Optional<BdsmMitspieler> first = mitspielerList.stream().filter(m -> m.getId().equals(id)).findFirst();
return first.orElse(null);
}
}

View File

@@ -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);

View File

@@ -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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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<Void> 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<Void> 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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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<Void> 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<Integer> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = new ArrayList<>();
@@ -776,10 +757,7 @@ public class CardLockController {
@Transactional
@DeleteMapping("/invitations/mine/{token}")
public ResponseEntity<Void> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = new ArrayList<>();
@@ -838,10 +813,7 @@ public class CardLockController {
@Transactional
@DeleteMapping("/invitations/sent/{token}")
public ResponseEntity<Void> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = new ArrayList<>();
@@ -898,10 +867,7 @@ public class CardLockController {
@GetMapping("/as-keyholder/{lockId}")
public ResponseEntity<Map<String, Object>> 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<Void> 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<Void> 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<Map<String, String>> 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<List<Map<String, Object>>> 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<Map<String, Object>> 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");
}
}

View File

@@ -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<Map<String, Object>>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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();

View File

@@ -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() {

View File

@@ -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<Map<String, Object>> 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();

View File

@@ -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<Map<String, Object>> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = templateRepository.findByOwner(myId).stream()
.map(t -> toPublicDto(t, myId, Set.of()))
@@ -113,9 +111,7 @@ public class TemplateExploreController {
@GetMapping("/subscribed")
public ResponseEntity<List<Map<String, Object>>> 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<TemplateSubscriptionEntity> subs = subscriptionRepository.findByUserId(myId);
Set<UUID> subscribedIds = subs.stream().map(TemplateSubscriptionEntity::getTemplateId).collect(Collectors.toSet());
@@ -136,9 +132,7 @@ public class TemplateExploreController {
@PostMapping("/{id}/subscribe")
@Transactional
public ResponseEntity<Void> 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<Void> 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<Map<String, Object>> 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<Void> 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<Void> 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();

View File

@@ -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<CommunityTaskVoteDisplayDTO> 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<Void> 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())

View File

@@ -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());
}
}

View File

@@ -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<Void> 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<Void> 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);

View File

@@ -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<List<Map<String, Object>>> 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<Map<String, Object>> result = offerRepository.findByOffererId(myId).stream()
.map(this::toDto)
@@ -102,9 +104,7 @@ public class KeyholderOfferController {
@Transactional
public ResponseEntity<Map<String, Object>> 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<Void> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = offerRepository.findByOffererId(userId).stream()
.map(o -> toPublicDto(o, myId))
@@ -212,9 +206,7 @@ public class KeyholderOfferController {
@GetMapping("/public")
public ResponseEntity<List<Map<String, Object>>> 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

View File

@@ -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<List<Map<String, Object>>> 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();
}

View File

@@ -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");
}
}
}

View File

@@ -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<Integer> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = new ArrayList<>();
@@ -108,9 +123,7 @@ public class LockeeInvitationController {
@GetMapping("/invitations/sent")
public ResponseEntity<List<Map<String, Object>>> 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<Map<String, Object>> result = new ArrayList<>();
@@ -138,9 +151,7 @@ public class LockeeInvitationController {
@DeleteMapping("/invitations/sent/{token}")
@Transactional
public ResponseEntity<Void> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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);

View File

@@ -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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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<Void> 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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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<Void> 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<List<Map<String, Object>>> 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<Map<String, Object>> result = new ArrayList<>();
@@ -670,9 +651,7 @@ public class TimeLockController {
@GetMapping("/timelock/as-keyholder/{lockId}")
public ResponseEntity<Map<String, Object>> 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();
}

View File

@@ -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<Map<String, Object>>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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();

View File

@@ -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));
}

View File

@@ -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;
}

View File

@@ -0,0 +1,6 @@
package de.oaa.xxx.games.common.aufgaben;
public interface CommonMitspieler {
boolean isVerfuegbar(Werkzeug werkzeug);
}

View File

@@ -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)) {

View File

@@ -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;

View File

@@ -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<Werkzeug> benoetigtPassiv;
private List<Toy> 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;
}

View File

@@ -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<List<Map<String, Object>>> 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 -> {

View File

@@ -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<VanillaAufgabeAnzeige> getFinisher() {
var list = new ArrayList<VanillaAufgabeAnzeige>();
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<Aufgabe> 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<VanillaMitspieler> 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 : "");

View File

@@ -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<RolleEnum> rollen;
private List<GeschlechtEnum> spieltMit;
private List<Werkzeug> verfuegbareWerkzeuge;
private boolean eigenesGeraet;

View File

@@ -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<AufgabenGruppe> 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<Void> 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<Void> 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);
}
}

View File

@@ -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();
}

View File

@@ -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<AufgabenGruppeList> getAll(@RequestParam(required = false) String search) {
UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public ResponseEntity<AufgabenGruppeList> 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<AufgabenGruppe> all, int page, int size) {

View File

@@ -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<Integer> 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<List<Map<String, Object>>> 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;
}

View File

@@ -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<FavoritList> all() {
UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public ResponseEntity<FavoritList> all(Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
List<FavoritEntity> 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<Void> create(@RequestBody Favorit favorit) {
UUID userId = (UUID) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public ResponseEntity<Void> 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<Void> delete(@RequestBody Favorit favorit) {
public ResponseEntity<Void> 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();

View File

@@ -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<Void> 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<Void> 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<Void> 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<Void> 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<Map<String, Object>> 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();

View File

@@ -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<Map<String, Object>> 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<Void> 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<Void> 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();
}

View File

@@ -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<ToyEntity> 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<List<Toy>> 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<ToyEntity> own = toyRepository.findByUserId(user.getUserId(), PageRequest.of(0, 500, Sort.by("name"))).getContent();
List<ToyEntity> 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<Void> 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<Void> 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();

View File

@@ -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<Werkzeug> 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<GeschlechtEnum> 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<RolleEnum> 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<Werkzeug> 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;
}
}

View File

@@ -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<GruppeDto> result = gruppeRepository.findByNameContainingIgnoreCase(q)
.stream()
.limit(30)
List<GruppeEntity> gruppen = gruppeRepository.findByNameContainingIgnoreCase(q)
.stream().limit(30).toList();
List<UUID> gruppeIds = gruppen.stream().map(GruppeEntity::getGruppeId).toList();
Map<UUID, LocalDateTime> latestActivity = buildLatestActivityMap(gruppeIds);
List<GruppeDto> 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<GruppeDto> result = mitgliedRepository.findByUserId(myId)
List<GruppeEntity> gruppen = mitgliedRepository.findByUserId(myId)
.stream()
.map(m -> gruppeRepository.findById(m.getGruppeId()).orElse(null))
.filter(Objects::nonNull)
.toList();
List<UUID> gruppeIds = gruppen.stream().map(GruppeEntity::getGruppeId).toList();
Map<UUID, LocalDateTime> latestActivity = buildLatestActivityMap(gruppeIds);
List<GruppeDto> 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<UUID, LocalDateTime> buildLatestActivityMap(List<UUID> gruppeIds) {
if (gruppeIds.isEmpty()) return Map.of();
Map<UUID, LocalDateTime> 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) {

View File

@@ -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<String> optionen, List<String> 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) {

View File

@@ -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<GruppenbeitragEn
List<GruppenbeitragEntity> findByGruppeIdInAndCreatedAtAfterOrderByCreatedAtDesc(List<UUID> gruppeIds, LocalDateTime since);
@Query("SELECT b.gruppeId, MAX(b.createdAt) FROM GruppenbeitragEntity b WHERE b.gruppeId IN :gruppeIds GROUP BY b.gruppeId")
List<Object[]> findLatestCreatedAtByGruppeIds(@Param("gruppeIds") List<UUID> gruppeIds);
@Transactional
void deleteByGruppeId(UUID gruppeId);

View File

@@ -178,7 +178,7 @@ public class MailTemplateService {
""".formatted(baseUrl, targetUrl, colorPrimary)
: "<div style=\"margin:0 0 2rem 0;\"></div>";
String settingsUrl = baseUrl + "/einstellungen.html#sec-benachrichtigungen";
String settingsUrl = baseUrl + "/konto/einstellungen.html#sec-benachrichtigungen";
return """
<!DOCTYPE html>

View File

@@ -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<Void> 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();
}

View File

@@ -46,10 +46,19 @@ public class RegistrationController {
@PostMapping
public ResponseEntity<String> 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()) {

View File

@@ -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());
}
}

View File

@@ -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<KommentarDto> dtos = kommentarRepository
.findByTargetTypeAndTargetIdOrderByCreatedAtAsc(targetType, targetId)
@@ -56,9 +60,7 @@ public class KommentarController {
@PostMapping
public ResponseEntity<KommentarDto> 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<Void> 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<Void> 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();
}

View File

@@ -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);
}
}
}

View File

@@ -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<List<Map<String, Object>>> 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<Map<String, Object>> result = messageRepository
.findNotificationsForUser(myId, PageRequest.of(0, 10))
@@ -52,9 +54,7 @@ public class NotificationController {
@GetMapping("/unread/count")
public ResponseEntity<Long> 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<Void> 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<Void> 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();
}

View File

@@ -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<List<PinnwandEintragDto>> 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<PinnwandEintragDto> dtos = eintragRepository
.findByProfilUserIdOrderByCreatedAtDesc(userId)
@@ -57,9 +61,7 @@ public class PinnwandController {
@PostMapping
public ResponseEntity<PinnwandEintragDto> 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<Void> 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<Void> 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();
}

View File

@@ -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<ProfileImageDto> 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<List<ProfileImageDto>> 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<ProfileImageEntity> images = profileImageRepository.findByUserIdOrderByUploadedAtDesc(userId);
List<ProfileImageDto> dtos = images.stream().map(img -> toDto(img, myId)).toList();
@@ -74,9 +72,7 @@ public class ProfileImageController {
@DeleteMapping("/{imageId}")
public ResponseEntity<Void> 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<Void> 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();
}

View File

@@ -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<UserProfile> 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<List<UserProfile>> 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<UserEntity> results = userRepository.findByNameContainingIgnoreCase(q);
List<UserProfile> profiles = results.stream()
@@ -84,9 +84,8 @@ public class SocialController {
@PostMapping("/friends/request")
public ResponseEntity<Void> 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<Void> 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<Void> 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<List<UserProfile>> getFriendsOfUser(@PathVariable UUID userId, Principal principal) {
if (userRepository.findByEmail(principal.getName()).isEmpty()) return ResponseEntity.status(401).build();
userService.requireUser(principal);
List<UserProfile> 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<List<FriendshipDto>> 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<FriendshipDto> dtos = friendshipRepository.findFriends(myId, Status.ACCEPTED).stream()
.map(f -> {
@@ -185,9 +178,7 @@ public class SocialController {
@GetMapping("/friends/pending")
public ResponseEntity<List<FriendshipDto>> 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<FriendshipDto> 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<Long> 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<Void> 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<List<ConversationSummary>> 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<MessageEntity> allMessages = messageRepository.findAllByUser(myId);
@@ -274,9 +259,7 @@ public class SocialController {
@GetMapping("/messages/unread/count")
public ResponseEntity<Long> 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);

View File

@@ -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<Map<String, Object>> 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<String, Object> result = new LinkedHashMap<>();
limitService.getActiveSubscription(userId).ifPresentOrElse(sub -> {

View File

@@ -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")

View File

@@ -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;

View File

@@ -103,20 +103,17 @@ public class UserController {
@PutMapping("/me/picture")
public ResponseEntity<Void> 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<Void> 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<Void> 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<Map<String, Object>> 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<String, NotificationPreferenceEntity> 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<Void> updateNotifications(@RequestBody Map<String, NotificationPreferenceRequest> 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<Map<String, Object>> 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<String, Object> 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<Void> 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<Void> 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<TtlockUserConfigDto> 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<Void> 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<Map<String, Object>> 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<Map<String, Object>> 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<Void> 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();

View File

@@ -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).

View File

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/neubdsm.html">
<title>BDSM Game xXx Sphere</title>
</head>
<body>
<script>window.location.replace('/neubdsm.html');</script>
</body>
</html>

View File

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/neubdsm.html">
<title>BDSM Game xXx Sphere</title>
</head>
<body>
<script>window.location.replace('/neubdsm.html');</script>
</body>
</html>

View File

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/neubdsm.html">
<title>BDSM Game xXx Sphere</title>
</head>
<body>
<script>window.location.replace('/neubdsm.html');</script>
</body>
</html>

View File

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/neubdsm.html">
<title>BDSM Game xXx Sphere</title>
</head>
<body>
<script>window.location.replace('/neubdsm.html');</script>
</body>
</html>

View File

@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/neubdsm.html">
<title>BDSM Game xXx Sphere</title>
</head>
<body>
<script>window.location.replace('/neubdsm.html');</script>
</body>
</html>

View File

@@ -651,14 +651,14 @@
const actions = document.getElementById('profileActions');
const isViewingOwnProfile = myUserId && myUserId === profile.userId;
if (isOwnProfile) {
actions.innerHTML = `<a href="/profile.html" class="btn">Profil bearbeiten</a>`;
actions.innerHTML = `<a href="/konto/profile.html" class="btn">Profil bearbeiten</a>`;
} else if (isViewingOwnProfile) {
// eigenes Profil im Preview-Modus keine Aktionsbuttons anzeigen
actions.innerHTML = '';
} else {
let html = '';
if (profile.friendStatus === 'FRIEND') {
html += `<a href="/nachrichten.html?userId=${profile.userId}" class="btn">✉ Nachricht</a>`;
html += `<a href="/community/nachrichten.html?userId=${profile.userId}" class="btn">✉ Nachricht</a>`;
} else if (profile.friendStatus === 'PENDING_SENT') {
html += `<button disabled>Anfrage gesendet</button>`;
} 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 = `<span>${label}</span><a href="/einstellungen.html" style="font-size:0.82rem;color:var(--color-primary);">← Einstellungen</a>`;
banner.innerHTML = `<span>${label}</span><a href="/konto/einstellungen.html" style="font-size:0.82rem;color:var(--color-primary);">← Einstellungen</a>`;
document.getElementById('profileView').prepend(banner);
}
@@ -806,7 +806,7 @@
const pic = f.profilePicture
? `<img src="data:image/png;base64,${f.profilePicture}" alt="${esc(f.name)}">`
: `<div class="friend-avatar-placeholder">👤</div>`;
return `<div class="friend-thumb" onclick="window.location='/benutzer.html?userId=${f.userId}'">
return `<div class="friend-thumb" onclick="window.location='/community/benutzer.html?userId=${f.userId}'">
${pic}
<span title="${esc(f.name)}">${esc(f.name)}</span>
</div>`;
@@ -968,7 +968,7 @@
const img = p.picture
? `<img src="data:image/png;base64,${p.picture}" style="width:40px;height:40px;border-radius:50%;object-fit:cover;display:block;">`
: `<div style="width:40px;height:40px;border-radius:50%;background:var(--color-secondary);display:flex;align-items:center;justify-content:center;font-size:1.1rem;flex-shrink:0;">👤</div>`;
return `<a href="/benutzer.html?userId=${esc(p.userId)}" style="position:relative;flex-shrink:0;text-decoration:none;" title="${esc(p.name || '')} (${p.role})">
return `<a href="/community/benutzer.html?userId=${esc(p.userId)}" style="position:relative;flex-shrink:0;text-decoration:none;" title="${esc(p.name || '')} (${p.role})">
${img}
${badge ? `<span style="position:absolute;top:-4px;right:-4px;font-size:0.9rem;line-height:1;">${badge}</span>` : ''}
</a>`;

View File

@@ -255,6 +255,30 @@
</div>
</div>
<!-- Vanilla-Einladungs-Dialog -->
<div class="lockee-dialog-bg" id="vanillaInviteDialog">
<div class="lockee-dialog-overlay" onclick="closeVanillaInviteDialog()"></div>
<div class="lockee-dialog-box">
<button onclick="closeVanillaInviteDialog()" style="position:absolute;top:0.75rem;right:0.75rem;background:none;border:none;color:var(--color-muted);font-size:1.3rem;cursor:pointer;padding:0.2rem 0.5rem;line-height:1;" title="Schließen"></button>
<div class="lockee-dialog-header">
<div class="lockee-dialog-avatar">🎲</div>
<div>
<div class="lockee-dialog-title" id="vanillaDialogTitle"></div>
<div class="lockee-dialog-sub">Vanilla Game Einladung</div>
</div>
</div>
<p style="font-size:0.88rem;color:var(--color-muted);line-height:1.5;margin:0;">
Du wurdest zu einem Vanilla Game eingeladen. Wie möchtest du mitspielen?
</p>
<div class="lockee-dialog-error" id="vanillaDialogError"></div>
<div class="lockee-dialog-actions" style="flex-direction:column;gap:0.5rem;">
<button class="btn-accept" style="width:100%;" onclick="acceptVanillaOwnDevice()">Am eigenen Gerät mitspielen</button>
<button class="btn-accept" style="width:100%;background:#1a5c8a!important;" onclick="acceptVanillaHostDevice()">Am Gerät des Hosts mitspielen</button>
<button class="btn-decline" style="width:100%;" onclick="declineVanillaFromDialog()">Einladung ablehnen</button>
</div>
</div>
</div>
<!-- BDSM-Einladungs-Dialog -->
<div class="lockee-dialog-bg" id="bdsmInviteDialog">
<div class="lockee-dialog-overlay" onclick="closeBdsmInviteDialog()"></div>
@@ -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
? `<div class="inv-avatar"><img src="data:image/jpeg;base64,${picBase64}" alt=""></div>`
: `<div class="inv-avatar">👤</div>`;
@@ -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 @@
<button onclick="declineKhInvitation('${esc(inv.token)}', this)" style="margin:0;padding:0.45rem 1rem;font-size:0.85rem;width:auto;background:#c0392b;border:none;color:#fff;border-radius:6px;font-weight:600;cursor:pointer;">✕ Ablehnen</button>
<a href="/keyholder/invitation/${esc(inv.token)}" style="display:block;text-align:center;padding:0.45rem 1rem;font-size:0.85rem;background:var(--color-success);color:#fff;border-radius:6px;text-decoration:none;font-weight:600;">✓ Annehmen</a>
</div>`;
} else if (inv._type === 'vanilla') {
typeLabel = 'Vanilla Game';
line2 = 'Spieleinladung';
actions = `
<div style="display:flex;flex-direction:column;gap:0.4rem;flex-shrink:0;">
<button onclick="openVanillaInviteDialog('${esc(inv.einladungId)}', '${esc(inv._otherName)}')" style="margin:0;padding:0.45rem 1rem;font-size:0.85rem;width:auto;background:var(--color-success,#27ae60);border:none;color:#fff;border-radius:6px;font-weight:600;cursor:pointer;">🎲 Details</button>
</div>`;
} 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
? ' &nbsp;<span style="font-size:0.72rem;">👁 Details sichtbar</span>'
: ' &nbsp;<span style="font-size:0.72rem;">🙈 Details verborgen</span>';
} 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}
<div class="inv-body">
<div class="inv-line1">${esc(inv._otherName)}</div>
<div class="inv-line2">${rolePrefix2}${esc(inv.lockName)}</div>
<div class="inv-line2">${line2sent}</div>
<div class="inv-line3">${typeLabel} · ${fmtDate(inv.createdAt)}${extra}</div>
</div>
<div style="flex-shrink:0;">
<button onclick="cancelSentInvitation('${esc(inv.token)}', '${inv._type}', this)" style="margin:0;padding:0.45rem 1rem;font-size:0.85rem;width:auto;background:#c0392b;border:none;color:#fff;border-radius:6px;font-weight:600;cursor:pointer;">✕ Zurückziehen</button>
<button onclick="cancelSentInvitation('${esc(inv._key)}', '${inv._type}', this)" style="margin:0;padding:0.45rem 1rem;font-size:0.85rem;width:auto;background:#c0392b;border:none;color:#fff;border-radius:6px;font-weight:600;cursor:pointer;">✕ Zurückziehen</button>
</div>`;
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();
}

View File

@@ -246,7 +246,7 @@
: '◉';
const privacyLabel = !p.isPublic ? ' <span style="font-size:0.7rem;color:var(--color-muted);">🔒</span>' : '';
const groupBadge = p.postType === 'GROUP' && p.gruppeId
? `<span class="gruppe-badge" onclick="event.stopPropagation()">👥 <a href="/gruppe.html?id=${p.gruppeId}" onclick="event.stopPropagation()">${esc(p.gruppeName)}</a></span>`
? `<span class="gruppe-badge" onclick="event.stopPropagation()">👥 <a href="/community/gruppe.html?id=${p.gruppeId}" onclick="event.stopPropagation()">${esc(p.gruppeName)}</a></span>`
: '';
const bildHtml = bilderCarousel(p.bilder, p.postId);
@@ -276,7 +276,7 @@
<div class="post-header">
<div class="post-avatar">${avatarHtml}</div>
<div>
<div class="post-author"><a href="/benutzer.html?userId=${p.authorId}" style="color:inherit;text-decoration:none;" onclick="event.stopPropagation()">${esc(p.authorName)}</a>${privacyLabel}</div>
<div class="post-author"><a href="/community/benutzer.html?userId=${p.authorId}" style="color:inherit;text-decoration:none;" onclick="event.stopPropagation()">${esc(p.authorName)}</a>${privacyLabel}</div>
<div class="post-meta">${fmtDate(p.createdAt)}${groupBadge}</div>
</div>
${deleteBtn}

View File

@@ -143,7 +143,7 @@
<!-- Friends tab -->
<div class="tab-panel active" id="tab-friends">
<ul class="user-list" id="friendsList"></ul>
<p class="empty-hint" id="friendsEmpty" style="display:none;">Du hast noch keine Freunde. <a href="/personen-suchen.html" style="color:var(--color-primary);">Personen suchen</a></p>
<p class="empty-hint" id="friendsEmpty" style="display:none;">Du hast noch keine Freunde. <a href="/community/personen-suchen.html" style="color:var(--color-primary);">Personen suchen</a></p>
</div>
<!-- Pending tab -->
@@ -210,12 +210,12 @@
friends.forEach(f => {
list.insertAdjacentHTML('beforeend', `
<li class="user-item" id="friend-${f.friendshipId}">
<a href="/benutzer.html?userId=${f.user.userId}" class="user-profile-link">
<a href="/community/benutzer.html?userId=${f.user.userId}" class="user-profile-link">
<div class="user-avatar">${avatar(f.user)}</div>
<div class="user-name">${esc(f.user.name)}</div>
</a>
<div class="user-actions">
<a href="/nachrichten.html?userId=${f.user.userId}" class="btn" style="background:var(--color-secondary); color:var(--color-text);">✉ Nachricht</a>
<a href="/community/nachrichten.html?userId=${f.user.userId}" class="btn" style="background:var(--color-secondary); color:var(--color-text);">✉ Nachricht</a>
<button class="btn-reject" onclick="removeFriend('${f.friendshipId}', this)">Entfernen</button>
</div>
</li>`);
@@ -247,7 +247,7 @@
pending.forEach(f => {
list.insertAdjacentHTML('beforeend', `
<li class="user-item" id="pending-${f.friendshipId}">
<a href="/benutzer.html?userId=${f.user.userId}" class="user-profile-link">
<a href="/community/benutzer.html?userId=${f.user.userId}" class="user-profile-link">
<div class="user-avatar">${avatar(f.user)}</div>
<div class="user-name">${esc(f.user.name)}</div>
</a>

View File

@@ -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 = `<button disabled style="opacity:0.6;">Anfrage ausstehend</button>`;
} else {
ha.innerHTML = `<a href="/gruppen.html" class="btn secondary">← Zurück</a>`;
ha.innerHTML = `<a href="/community/gruppen.html" class="btn secondary">← Zurück</a>`;
}
// Admin tab
@@ -495,7 +495,7 @@
<div class="post-header">
<div class="post-avatar">${av}</div>
<div>
<div class="post-author"><a href="/benutzer.html?userId=${p.authorId}" style="color:inherit;text-decoration:none;" onclick="event.stopPropagation()">${esc(p.authorName)}</a></div>
<div class="post-author"><a href="/community/benutzer.html?userId=${p.authorId}" style="color:inherit;text-decoration:none;" onclick="event.stopPropagation()">${esc(p.authorName)}</a></div>
</div>
<div class="post-date">${fmtDate(p.createdAt)}</div>
</div>
@@ -686,7 +686,7 @@
list.insertAdjacentHTML('beforeend', `
<li class="member-item" id="member-${m.userId}">
<div class="member-avatar">${av}</div>
<a href="/benutzer.html?userId=${m.userId}" class="member-name" style="text-decoration:none;color:inherit;">${esc(m.userName)}</a>
<a href="/community/benutzer.html?userId=${m.userId}" class="member-name" style="text-decoration:none;color:inherit;">${esc(m.userName)}</a>
${roleBadge}
${actions}
</li>`);
@@ -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 @@
<div class="post-header">
<div class="post-avatar">${av}</div>
<div>
<div class="post-author"><a href="/benutzer.html?userId=${p.authorId}" style="color:inherit;text-decoration:none;">${esc(p.authorName)}</a></div>
<div class="post-author"><a href="/community/benutzer.html?userId=${p.authorId}" style="color:inherit;text-decoration:none;">${esc(p.authorName)}</a></div>
<div class="post-date">${fmtDate(p.createdAt)}</div>
</div>
</div>

View File

@@ -176,7 +176,7 @@
}
}
return `
<div class="gruppe-card" id="gc-${g.gruppeId}" onclick="location.href='/gruppe.html?gruppeId=${g.gruppeId}'" style="cursor:pointer;">
<div class="gruppe-card" id="gc-${g.gruppeId}" onclick="location.href='/community/gruppe.html?gruppeId=${g.gruppeId}'" style="cursor:pointer;">
${img}
<div class="gruppe-card-body">
<div class="gruppe-card-name">${esc(g.name)}${privBadge} ${roleBadge}</div>
@@ -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.');
}

View File

@@ -359,7 +359,7 @@
const list = document.getElementById('convList');
list.innerHTML = '';
if (convs.length === 0) {
list.innerHTML = '<li style="padding:1rem; color:var(--color-muted); font-size:0.9rem;">Noch keine Nachrichten. <a href="/personen-suchen.html" style="color:var(--color-primary);">Personen suchen</a></li>';
list.innerHTML = '<li style="padding:1rem; color:var(--color-muted); font-size:0.9rem;">Noch keine Nachrichten. <a href="/community/personen-suchen.html" style="color:var(--color-primary);">Personen suchen</a></li>';
return;
}
convs.forEach(c => {
@@ -403,7 +403,7 @@
partnerName = convItem ? convItem.querySelector('.conv-name').textContent : '…';
}
document.getElementById('threadPartnerName').innerHTML =
`<a href="/benutzer.html?userId=${partnerId}" style="color:inherit;text-decoration:none;">${esc(partnerName)}</a>`;
`<a href="/community/benutzer.html?userId=${partnerId}" style="color:inherit;text-decoration:none;">${esc(partnerName)}</a>`;
const avatarEl = document.getElementById('threadPartnerAvatar');
if (partnerPic) {

View File

@@ -127,7 +127,7 @@
: '◉';
list.insertAdjacentHTML('beforeend', `
<li class="user-item" data-user-id="${u.userId}">
<a href="/benutzer.html?userId=${u.userId}" class="user-profile-link">
<a href="/community/benutzer.html?userId=${u.userId}" class="user-profile-link">
<div class="user-avatar">${avatar}</div>
<div class="user-name">${esc(u.name)}</div>
</a>
@@ -138,7 +138,7 @@
function buildActions(u) {
if (u.friendStatus === 'FRIEND') {
return `<a href="/nachrichten.html?userId=${u.userId}" class="btn" style="background:var(--color-secondary); color:var(--color-text);">✉ Nachricht</a>`;
return `<a href="/community/nachrichten.html?userId=${u.userId}" class="btn" style="background:var(--color-secondary); color:var(--color-text);">✉ Nachricht</a>`;
}
if (u.friendStatus === 'PENDING_SENT') {
return `<button disabled>Anfrage gesendet</button>`;
@@ -184,7 +184,7 @@
const item = btn.closest('.user-item');
if (item) {
item.querySelector('.user-actions').innerHTML =
`<a href="/nachrichten.html?userId=${senderId}" class="btn" style="background:var(--color-secondary); color:var(--color-text);">✉ Nachricht</a>`;
`<a href="/community/nachrichten.html?userId=${senderId}" class="btn" style="background:var(--color-secondary); color:var(--color-text);">✉ Nachricht</a>`;
}
} else {
btn.disabled = false;

View File

@@ -98,7 +98,7 @@
document.getElementById('sub').textContent = 'Du hast die Einladung abgelehnt.';
document.getElementById('actions').innerHTML = '<button onclick="window.location.href=\'/userhome.html\'">Zur Startseite</button>';
} else if (mode === 'OWN_DEVICE') {
window.location.replace(`/neubdsm.html`);
window.location.replace(`/games/bdsm/neubdsm.html`);
} else {
zeigeBestaetigt();
}

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/games/bdsm/neubdsm.html">
<title>BDSM Game xXx Sphere</title>
</head>
<body>
<script>window.location.replace('/games/bdsm/neubdsm.html');</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More