From 03118d339a9aa073e2f201653dc7cb85e8ee98aa Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 25 Mar 2026 23:54:47 +0100 Subject: [PATCH] Weiter am Timelock gearbeitet --- .claude/settings.local.json | 14 +- .metadata/.lock_info | 4 +- .metadata/.log | 65 + .../.safetable/org.eclipse.core.resources | Bin 910 -> 1310 bytes .../org.eclipse.e4.workbench/workbench.xmi | 3919 ++++++++--------- .../.plugins/org.eclipse.m2e.logback/0.log | 1 + .metadata/version.ini | 2 +- xxxthegame/src/main/java/Ideen.txt | 8 - .../games/chastity/common/BaseLockEntity.java | 2 +- .../chastity/timelock/TimeLockController.java | 139 +- .../chastity/timelock/TimeLockRepository.java | 5 +- .../main/resources/static/activetimelock.html | 52 +- .../src/main/resources/static/js/icons.js | 61 +- .../src/main/resources/static/keyholder.html | 118 +- .../main/resources/static/meine-locks.html | 16 +- .../src/main/resources/static/neulock.html | 40 + 16 files changed, 2417 insertions(+), 2029 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 46c036b..3f3c91d 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -40,7 +40,19 @@ "Bash(stat /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/ttlock/*)", "Bash(git -C /home/mario/Workspaces/xxx-thegame diff HEAD xxxthegame/src/main/resources/static/neulock.html)", "Bash(1:*)", - "Bash(python3:*)" + "Bash(python3:*)", + "Bash(head -8 echo \"---\" grep -n \"✎\\\\|edit\\\\|bearbeit\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/aufgaben.html)", + "Bash(head -8 echo \"---\" grep -n \"🚿\\\\|hygiene\\\\|hygien\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/activelock.html)", + "Bash(head -8 echo \"---\" grep -n \"πŸ†˜\\\\|SOS\\\\|nothilfe\\\\|emer\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/activelock.html)", + "Bash(head -8 echo \"---\" grep -n \"πŸ‘\\\\|πŸ‘Ž\\\\|vote\\\\|abstimm\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/communityvotes.html)", + "Bash(head -8 echo \"---\" grep -n \"🧊\\\\|ice\\\\|eis\\\\|freeze\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/activetimelock.html)", + "Bash(head -8 echo \"---\" grep -n \"πŸ“\\\\|folder\\\\|archiv\\\\|histor\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/activelock.html)", + "Bash(head -8 echo \"---\" grep -n \"πŸ”„\\\\|refresh\\\\|reload\\\\|neu laden\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/activelock.html)", + "Bash(head -8 echo \"---\" grep -n \"πŸ”₯\\\\|fire\\\\|hot\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/nachrichten.html)", + "Bash(head -5 echo \"---\" grep -n \"⬆\\\\|⬇\\\\|sort\\\\|up\\\\|down\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/admin.html)", + "Bash(head -8 echo \"---\" grep -n \"⭐\\\\|star\\\\|premium\\\\|abo\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/abonnements.html)", + "Bash(head -8 echo \"---\" grep -n \"πŸ‘\\\\|view\\\\|sichtbar\\\\|Ansicht\" /home/mario/Workspaces/xxx-thegame/xxxthegame/src/main/resources/static/einladungen.html)", + "Bash(/dev/null echo:*)" ] } } diff --git a/.metadata/.lock_info b/.metadata/.lock_info index 052839f..2cfd875 100644 --- a/.metadata/.lock_info +++ b/.metadata/.lock_info @@ -1,5 +1,5 @@ -#Wed Mar 25 07:26:10 CET 2026 +#Wed Mar 25 21:32:43 CET 2026 display=\:0 host=mario-mint -process-id=4033 +process-id=43084 user=mario diff --git a/.metadata/.log b/.metadata/.log index f4053ce..9b36c3a 100644 --- a/.metadata/.log +++ b/.metadata/.log @@ -754,3 +754,68 @@ Binding(CTRL+SHIFT+T, !ENTRY org.springframework.tooling.boot.ls 1 0 2026-03-25 16:28:18.002 !MESSAGE DelegatingStreamConnectionProvider - Stopping Boot LS +!SESSION 2026-03-25 21:32:37.936 ----------------------------------------------- +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-25 21:32:39.444 +!MESSAGE Activated before the state location was initialized. Retry after the state location is initialized. + +!ENTRY ch.qos.logback.classic 1 0 2026-03-25 21:32:44.209 +!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-25 21:32:44.327 +!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-25 21:32:44.327 +!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-25 21:32:44.476 +!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-25 21:32:44.476 +!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-25 21:33:18.884 +!MESSAGE Keybinding conflicts occurred. They may interfere with normal accelerator operation. +!SUBENTRY 1 org.eclipse.jface 2 0 2026-03-25 21:33:18.884 +!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.jface 2 0 2026-03-25 22:47:11.586 +!MESSAGE Keybinding conflicts occurred. They may interfere with normal accelerator operation. +!SUBENTRY 1 org.eclipse.jface 2 0 2026-03-25 22:47:11.586 +!MESSAGE A conflict occurred for CTRL+R: +Binding(CTRL+R, + ParameterizedCommand(Command(org.eclipse.debug.ui.commands.RunToLine,Run to Line, + Resume and break when execution reaches the current line, + Category(org.eclipse.debug.ui.category.run,Run/Debug,Run/Debug command category,true), + WorkbenchHandlerServiceHandler("org.eclipse.debug.ui.commands.RunToLine"), + ,,true),null), + org.eclipse.ui.defaultAcceleratorConfiguration, + org.eclipse.debug.ui.debugging,,,system) +Binding(CTRL+R, + ParameterizedCommand(Command(org.springframework.ide.eclipse.boot.restart.commands.restart,Trigger Restart, + Restart Spring Boot Application, + Category(org.eclipse.debug.ui.category.run,Run/Debug,Run/Debug command category,true), + WorkbenchHandlerServiceHandler("org.springframework.ide.eclipse.boot.restart.commands.restart"), + ,,true),null), + org.eclipse.ui.defaultAcceleratorConfiguration, + org.eclipse.debug.ui.console,,,system) diff --git a/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources b/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources index cc86e3e61d4e0939f5ed5c53aa38c3f9306faaff..6a8ed2f9b9e845b213408591599daf68da272030 100644 GIT binary patch delta 45 zcmeBUpU1VKk9qQ8MlB8_Ln{+QD^ugiUm49dW=Jp!9EkY+S$PkGh*aR`p6cD@#{gYE B5d#1K delta 7 OcmbQo)yKY}j~M_8rUHKe diff --git a/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi b/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi index 3ccebc0..e1e5bde 100644 --- a/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi +++ b/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi @@ -1,8 +1,8 @@ - - + + activeSchemeId:org.eclipse.ui.defaultAcceleratorConfiguration - + @@ -11,9 +11,9 @@ topLevel shellMaximized - - - + + + persp.actionSet:org.eclipse.mylyn.tasks.ui.navigation persp.actionSet:org.eclipse.ui.cheatsheets.actionSet @@ -77,142 +77,148 @@ persp.newWizSC:org.eclipse.jdt.junit.wizards.NewTestCaseCreationWizard persp.actionSet:org.eclipse.jdt.junit.JUnitActionSet persp.viewSC:org.eclipse.ant.ui.views.AntView + persp.actionSet:org.eclipse.debug.ui.debugActionSet persp.editorOnboardingImageUri:platform:/plugin/org.eclipse.jdt.ui/$nl$/icons/full/onboarding_jperspective.svg persp.editorOnboardingText:Open a file or drop files here to open them. persp.editorOnboardingCommand:Find Actions$$$Ctrl+3 persp.editorOnboardingCommand:Show Key Assist$$$Shift+Ctrl+L persp.editorOnboardingCommand:New$$$Ctrl+N persp.editorOnboardingCommand:Open Type$$$Shift+Ctrl+T - persp.actionSet:org.eclipse.debug.ui.debugActionSet - - - - + + + + org.eclipse.e4.primaryNavigationStack - noFocus - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:Java - + Minimized - + View categoryTag:Spring - - + + View categoryTag:Git - - - - + + + + org.eclipse.e4.secondaryNavigationStack Minimized - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Mylyn - + View categoryTag:Java - + View categoryTag:Ant - + org.eclipse.e4.secondaryDataStack Oomph Gradle Debug Version Control (Team) - + active + noFocus + View categoryTag:General - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Terminal - + View categoryTag:Gradle - + View categoryTag:Gradle - + View categoryTag:Debug - + View categoryTag:Version Control (Team) + + View + categoryTag:Oomph + NoRestore + - + persp.actionSet:org.eclipse.mylyn.tasks.ui.navigation persp.actionSet:org.eclipse.ui.cheatsheets.actionSet @@ -261,100 +267,99 @@ persp.editorOnboardingCommand:Step Over$$$F6 persp.editorOnboardingCommand:Step Return$$$F7 persp.editorOnboardingCommand:Resume$$$F8 - - + + org.eclipse.e4.primaryNavigationStack - + View categoryTag:Debug - + View categoryTag:General - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Java - - - - + + + + org.eclipse.e4.secondaryNavigationStack - active - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Ant - - + + View categoryTag:General - + View categoryTag:General - + View categoryTag:Debug - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Terminal - + View categoryTag:Debug - + View categoryTag:General @@ -363,2743 +368,2707 @@ - - + + View categoryTag:Help - + View categoryTag:General - + View categoryTag:Help - + View categoryTag:Help - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:Help - - + + EditorStack - - - Editor - removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor - - - - Editor - removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor - - - - Editor - removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor - - - - Editor - removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor - - - - Editor - removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor - - - + + Editor removeOnHide org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide org.eclipse.ui.genericeditor.GenericEditor - - + + Editor removeOnHide org.eclipse.ui.genericeditor.GenericEditor - - - Editor - removeOnHide - org.eclipse.ui.genericeditor.GenericEditor - - - - Editor - removeOnHide - org.eclipse.ui.genericeditor.GenericEditor - - - - Editor - removeOnHide - org.eclipse.ui.genericeditor.GenericEditor - - - - Editor - removeOnHide - org.eclipse.ui.genericeditor.GenericEditor - - - + + Editor removeOnHide org.eclipse.jdt.ui.CompilationUnitEditor - - + + Editor removeOnHide org.eclipse.jdt.ui.CompilationUnitEditor - - + + Editor removeOnHide org.eclipse.jdt.ui.CompilationUnitEditor - - + + Editor removeOnHide - org.eclipse.jdt.ui.CompilationUnitEditor + org.eclipse.ui.genericeditor.GenericEditor - + View categoryTag:Java - + ViewMenu menuContribution:menu - + - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:Java - + View categoryTag:Java - + - + View categoryTag:General - highlighted - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + active + ViewMenu menuContribution:menu - + - + View categoryTag:General - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Mylyn - + View categoryTag:Terminal - + View categoryTag:Java - + View categoryTag:Git - + View categoryTag:Java - + View categoryTag:Spring - + ViewMenu menuContribution:menu - + - + View categoryTag:Ant - + View categoryTag:Gradle - + ViewMenu menuContribution:menu - + - + View categoryTag:Gradle - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + busy + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - active - activeOnClose - + ViewMenu menuContribution:menu - + - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Debug - + ViewMenu menuContribution:menu - + - + View categoryTag:Version Control (Team) - + ViewMenu menuContribution:menu - + - - + + + + + View + categoryTag:Oomph + NoRestore + + ViewMenu + menuContribution:menu + + + + + toolbarSeparator - + - + Draggable - + - + toolbarSeparator - + - + Draggable - - + + - + toolbarSeparator - + - + Draggable - + Draggable - + Draggable - + Draggable - + toolbarSeparator - + - + Draggable - + - - toolbarSeparator - - - - toolbarSeparator - - - + Draggable - + + Draggable + + + toolbarSeparator + + + + toolbarSeparator + + + + Draggable + + stretch SHOW_RESTORE_MENU - + Draggable HIDEABLE SHOW_RESTORE_MENU - - + + stretch - + Draggable - + Draggable - - + + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - - + + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - + TrimStack Draggable - - - - - - - - - - - - - - + + + + + + + + + + + + + + platform:gtk - - - - + + + + platform:gtk - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - + + + + + - - + + - - - - - - - - - + + + + + + + + + - - + + - - - + + + - - - - - + + + + + - - + + - - - + + + - - - + + + - - - - - - - - + + + + + + + + platform:gtk - - - - - + + + + + - - + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - + + + + + + + + - - + + - - - - - - + + + + + + - - - - - - + + + + + + - - + + - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Editor removeOnHide - + View categoryTag:Ant - + View categoryTag:Gradle - + View categoryTag:Gradle - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Debug - + View categoryTag:Java - + View categoryTag:Git - + View categoryTag:Git - + View categoryTag:Git - + View categoryTag:Git NoRestore - + View categoryTag:Git - + View categoryTag:Help - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Debug - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Java Browsing - + View categoryTag:Java Browsing - + View categoryTag:Java Browsing - + View categoryTag:Java Browsing - + View categoryTag:Java - + View categoryTag:General - + View categoryTag:Java - + View categoryTag:Java - + View categoryTag:Docker - + View categoryTag:Docker - + View categoryTag:Docker - + View categoryTag:Docker - + View categoryTag:Language Servers - + View categoryTag:Language Servers - + View categoryTag:Language Servers - + View categoryTag:Maven - + View categoryTag:Maven - + View categoryTag:Maven - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Mylyn - + View categoryTag:Oomph - + View categoryTag:Oomph NoRestore - + View categoryTag:Plug-in Development - + View categoryTag:General - + View categoryTag:Version Control (Team) - + View categoryTag:Version Control (Team) - + View categoryTag:Terminal - + View categoryTag:Help - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Help - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:General - + View categoryTag:Spring - + View categoryTag:Spring - + View categoryTag:Spring - - + + glue move_after:PerspectiveSpacer SHOW_RESTORE_MENU - + move_after:Spacer Glue HIDEABLE SHOW_RESTORE_MENU - + glue move_after:SearchField SHOW_RESTORE_MENU - - - - - + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.metadata/.plugins/org.eclipse.m2e.logback/0.log b/.metadata/.plugins/org.eclipse.m2e.logback/0.log index 7fbb4a0..1815cf6 100644 --- a/.metadata/.plugins/org.eclipse.m2e.logback/0.log +++ b/.metadata/.plugins/org.eclipse.m2e.logback/0.log @@ -8,3 +8,4 @@ 2026-03-24 06:41:47,661 [Worker-2: 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-24 11:26:24,107 [Worker-2: 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-25 07:26:14,133 [Worker-5: Loading available Gradle versions] INFO o.e.b.c.i.u.g.PublishedGradleVersions - Gradle version information cache is out-of-date. Trying to update. +2026-03-25 21:32:47,427 [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. diff --git a/.metadata/version.ini b/.metadata/version.ini index de1ba2c..62840ca 100644 --- a/.metadata/version.ini +++ b/.metadata/version.ini @@ -1,3 +1,3 @@ -#Wed Mar 25 07:26:10 CET 2026 +#Wed Mar 25 21:32:43 CET 2026 org.eclipse.core.runtime=2 org.eclipse.platform=4.39.0.v20260226-0420 diff --git a/xxxthegame/src/main/java/Ideen.txt b/xxxthegame/src/main/java/Ideen.txt index 2134d94..851ad46 100644 --- a/xxxthegame/src/main/java/Ideen.txt +++ b/xxxthegame/src/main/java/Ideen.txt @@ -1,13 +1,5 @@ -Anzeige der Locks und Lockees im Profil, Anzeige der Locked time, falls verifiziert, die verification muss einmal am tag statt finden - -Historie fΓΌr die Spiele - Sammeln von Erfahrung -VerknΓΌpfung der Spiele, wenn das Finish eines aus dem Bereich Chastity ist, wird daraus sofort ein Lock erstellt - -Wenn ein Lock fΓΌr einen User existiert, wird er ohne entsprechend Penis/Vagina zu dem Spiel erstellt. - TODO: Im Time Lock, wenn im Spinning Wheel tasks drin sind, dΓΌrfen keine sonst keine Tasks gefordert sein und umgekehrt Ich kann Spieler einladen zu spielen, dann kriegt die Person eine E-Mail und muss bestΓ€tigen, dass es diese PErson ist, sie wird dann ins spiel ΓΌbernommen diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockEntity.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockEntity.java index 381da7a..593499e 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockEntity.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/common/BaseLockEntity.java @@ -28,7 +28,7 @@ import lombok.Setter; @Getter @Setter @Entity -@Table(name = "current_lock") +@Table(name = "active_lock") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "lock_type", discriminatorType = DiscriminatorType.STRING) public class BaseLockEntity { diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java index 1d5f38b..03cfff4 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockController.java @@ -42,6 +42,7 @@ import de.oaa.xxx.games.chastity.lockee.LockeeInvitationEntity; import de.oaa.xxx.games.chastity.lockee.LockeeInvitationRepository; import de.oaa.xxx.games.chastity.spinningwheel.SpinningWheelEntry; 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; @@ -59,6 +60,7 @@ public class TimeLockController { private final CommunityVerificationRepository verificationRepository; private final CommunityVerificationVoteRepository verificationVoteRepository; private final SubscriptionLimitService subscriptionLimitService; + private final UnlockCodeHistoryService unlockCodeHistoryService; public TimeLockController(TimeLockRepository timeLockRepository, TimeLockTemplateRepository templateRepository, @@ -69,7 +71,8 @@ public class TimeLockController { TimeLockServiceFactory timeLockServiceFactory, CommunityVerificationRepository verificationRepository, CommunityVerificationVoteRepository verificationVoteRepository, - SubscriptionLimitService subscriptionLimitService) { + SubscriptionLimitService subscriptionLimitService, + UnlockCodeHistoryService unlockCodeHistoryService) { this.timeLockRepository = timeLockRepository; this.templateRepository = templateRepository; this.userRepository = userRepository; @@ -80,6 +83,7 @@ public class TimeLockController { this.verificationRepository = verificationRepository; this.verificationVoteRepository = verificationVoteRepository; this.subscriptionLimitService = subscriptionLimitService; + this.unlockCodeHistoryService = unlockCodeHistoryService; } // ── Erstellen ──────────────────────────────────────────────────────────────── @@ -357,7 +361,7 @@ public class TimeLockController { } result.put("keyholderRequestedUnlock", l.isKeyholderRequestedUnlock()); - if (l.isKeyholderRequestedUnlock() || l.isTestLock()) { + if (l.isKeyholderRequestedUnlock() || l.isTestLock() || timeUp) { result.put("unlockCode", l.getUnlockCode() != null ? l.getUnlockCode() : ""); } result.put("emergencyUnlockRequested", l.getEmergencyUnlockRequestedAt() != null); @@ -584,6 +588,10 @@ public class TimeLockController { } TimeLockService service = timeLockServiceFactory.create(l); + if (l.getUnlockCode() != null && !l.getUnlockCode().isBlank()) { + String reason = l.isKeyholderRequestedUnlock() ? "KEYHOLDER_UNLOCK" : "LOCK_OPEN"; + unlockCodeHistoryService.save(myId, lockId, l.getName(), l.getUnlockCode(), reason); + } service.unlock(l.getUnlockCode()); // Clean up verifications @@ -596,6 +604,123 @@ public class TimeLockController { return ResponseEntity.noContent().build(); } + // ── Keyholder-Ansicht ───────────────────────────────────────────────────────── + + @GetMapping("/timelock/as-keyholder") + public ResponseEntity>> getTimeLocksAsKeyholder(Principal principal) { + var meOpt = userRepository.findByEmail(principal.getName()); + if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); + UUID myId = meOpt.get().getUserId(); + + var locks = timeLockRepository.findByKeyholderAndStartTimeIsNotNullAndUnlockTimeIsNull(myId); + List> result = new ArrayList<>(); + for (var lock : locks) { + var lockeeOpt = userRepository.findById(lock.getLockee()); + if (lockeeOpt.isEmpty()) continue; + var lockee = lockeeOpt.get(); + LocalDateTime now = LocalDateTime.now(); + boolean isFrozen = lock.getFrozenFrom() != null + && (lock.getFrozenUntil() == null || lock.getFrozenUntil().isAfter(now)); + Map item = new LinkedHashMap<>(); + item.put("lockId", lock.getLockId().toString()); + item.put("lockType", "TIMELOCK"); + item.put("lockName", lock.getName() != null ? lock.getName() : "TimeLock"); + item.put("lockeeName", lockee.getName()); + item.put("lockeeId", lockee.getUserId().toString()); + item.put("lockeeProfilePic", lockee.getProfilePicture()); + item.put("startTime", lock.getStartTime() != null ? lock.getStartTime().toString() : null); + item.put("isFrozen", isFrozen); + item.put("emergencyUnlockRequested", lock.getEmergencyUnlockRequestedAt() != null); + result.add(item); + } + return ResponseEntity.ok(result); + } + + @GetMapping("/timelock/as-keyholder/{lockId}") + public ResponseEntity> getTimeLockAsKeyholder( + @PathVariable UUID lockId, Principal principal) { + var meOpt = userRepository.findByEmail(principal.getName()); + if (meOpt.isEmpty()) return ResponseEntity.status(401).build(); + UUID myId = meOpt.get().getUserId(); + + var lockOpt = timeLockRepository.findById(lockId); + if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); + var l = lockOpt.get(); + if (!myId.equals(l.getKeyholder())) return ResponseEntity.status(403).build(); + + var lockeeOpt = userRepository.findById(l.getLockee()); + if (lockeeOpt.isEmpty()) return ResponseEntity.notFound().build(); + var lockee = lockeeOpt.get(); + + LocalDateTime now = LocalDateTime.now(); + boolean timeUp = l.getUnlockTime() != null && l.getUnlockTime().isBefore(now); + boolean isFrozen = l.getFrozenFrom() != null + && (l.getFrozenUntil() == null || l.getFrozenUntil().isAfter(now)); + + // Verifikation + boolean verificationDue = false; + boolean verificationDoneToday = false; + String verificationMyVote = null; + String verificationTodayId = null; + if (l.isRequiresVerification()) { + LocalDateTime todayStart = LocalDate.now().atStartOfDay(); + LocalDateTime todayEnd = todayStart.plusDays(1); + var completed = verificationRepository + .findByLockIdAndCreatedAtBetweenAndImageIsNotNull(lockId, todayStart, todayEnd); + if (!completed.isEmpty()) { + verificationDoneToday = true; + var todayV = completed.get(0); + verificationTodayId = todayV.getDisplayId().toString(); + var myVote = verificationVoteRepository + .findAllByVerificationId(todayV.getDisplayId()).stream() + .filter(v -> myId.equals(v.getVoteId())).findFirst(); + verificationMyVote = myVote.map(v -> v.isUpvote() ? "upvote" : "downvote").orElse(null); + } else { + verificationDue = true; + } + } + + Map result = new LinkedHashMap<>(); + result.put("lockId", l.getLockId().toString()); + result.put("lockType", "TIMELOCK"); + result.put("lockName", l.getName() != null ? l.getName() : "TimeLock"); + result.put("lockeeId", lockee.getUserId().toString()); + result.put("lockeeName", lockee.getName()); + result.put("lockeeProfilePic", lockee.getProfilePicture()); + result.put("startTime", l.getStartTime() != null ? l.getStartTime().toString() : null); + result.put("unlockTime", (l.isEndTimeVisible() || timeUp) + ? (l.getUnlockTime() != null ? l.getUnlockTime().toString() : null) : null); + result.put("timeUp", timeUp); + result.put("isFrozen", isFrozen); + result.put("frozenUntil", l.getFrozenUntil() != null ? l.getFrozenUntil().toString() : null); + result.put("emergencyUnlockRequested", l.getEmergencyUnlockRequestedAt() != null); + result.put("keyholderRequestedUnlock", l.isKeyholderRequestedUnlock()); + result.put("requiresVerification", l.isRequiresVerification()); + result.put("verificationDue", verificationDue); + result.put("verificationDoneToday", verificationDoneToday); + result.put("verificationMyVote", verificationMyVote); + result.put("verificationTodayId", verificationTodayId); + return ResponseEntity.ok(result); + } + + @PostMapping("/timelock/as-keyholder/{lockId}/request-unlock") + @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(); + + var lockOpt = timeLockRepository.findById(lockId); + if (lockOpt.isEmpty()) return ResponseEntity.notFound().build(); + var l = lockOpt.get(); + if (!myId.equals(l.getKeyholder())) return ResponseEntity.status(403).build(); + + l.setKeyholderRequestedUnlock(true); + timeLockRepository.save(l); + return ResponseEntity.noContent().build(); + } + // ── Notfall-Entsperrung ─────────────────────────────────────────────────────── @PostMapping("/timelock/{lockId}/emergency-unlock") @@ -615,15 +740,21 @@ public class TimeLockController { l.setEmergencyUnlockRequestedAt(LocalDateTime.now()); if (l.getKeyholder() == null) { + // Kein Keyholder: sofort entsperren, Lock als ungΓΌltig markieren (keine Historie, keine XP) l.setEmergencyAutoUnlocked(true); l.setKeyholderRequestedUnlock(true); + timeLockRepository.save(l); + if (l.getUnlockCode() != null && !l.getUnlockCode().isBlank()) { + unlockCodeHistoryService.save(myId, lockId, l.getName(), l.getUnlockCode(), "EMERGENCY_UNLOCK"); + } + return ResponseEntity.ok(Map.of("unlockCode", l.getUnlockCode() != null ? l.getUnlockCode() : "")); } 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); + timeLockRepository.save(l); + return ResponseEntity.noContent().build(); } - timeLockRepository.save(l); - return ResponseEntity.noContent().build(); } // ── Hilfsmethoden ───────────────────────────────────────────────────────────── diff --git a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockRepository.java b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockRepository.java index b6f7cde..a8f0310 100644 --- a/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockRepository.java +++ b/xxxthegame/src/main/java/de/oaa/xxx/games/chastity/timelock/TimeLockRepository.java @@ -1,5 +1,6 @@ package de.oaa.xxx.games.chastity.timelock; +import java.util.List; import java.util.UUID; import org.springframework.data.jpa.repository.JpaRepository; @@ -10,7 +11,9 @@ public interface TimeLockRepository extends JpaRepository boolean existsByLockeeAndStartTimeIsNotNullAndUnlockTimeIsNull(UUID lockee); - @Modifying + List findByKeyholderAndStartTimeIsNotNullAndUnlockTimeIsNull(UUID keyholder); + + @Modifying(clearAutomatically = true) @Query("DELETE FROM TimeLockEntity t WHERE t.lockId = :lockId") void deleteByLockId(UUID lockId); } diff --git a/xxxthegame/src/main/resources/static/activetimelock.html b/xxxthegame/src/main/resources/static/activetimelock.html index 154f4b1..eac9b3f 100644 --- a/xxxthegame/src/main/resources/static/activetimelock.html +++ b/xxxthegame/src/main/resources/static/activetimelock.html @@ -1208,26 +1208,9 @@ async function lockLoeschen() { closeWarnModal(); try { - const res = await fetch('/keyholder/timelock/' + lockId, { method: 'DELETE' }); - if (res.ok) { - const data = await res.json().catch(() => ({})); - if (data.unlockCode) { - // Code kurz anzeigen bevor redirect - const area = document.getElementById('lockActionArea'); - area.innerHTML = ` -
-
Dein Entsperrcode:
-
${data.unlockCode}
-
Lock erfolgreich beendet.
-
`; - setTimeout(() => { window.location.href = '/userhome.html'; }, 5000); - } else { - window.location.href = '/userhome.html'; - } - } - } catch(_) { - window.location.href = '/userhome.html'; - } + await fetch('/keyholder/timelock/' + lockId, { method: 'DELETE' }); + } catch(_) { /* ignorieren */ } + window.location.href = '/userhome.html'; } function openEmergencyModal() { @@ -1253,13 +1236,30 @@ document.getElementById('emergencyModalActions').style.display = 'none'; try { const res = await fetch('/keyholder/timelock/' + lockId + '/emergency-unlock', { method: 'POST' }); - if (res.ok || res.status === 204) { - const hasKH2 = _currentLock && _currentLock.keyholderName; - const successText = hasKH2 - ? `βœ… Notfall-Anfrage gesendet. ${_currentLock.keyholderName} wurde benachrichtigt.` - : `βœ… Notfall-Freigabe ausgelΓΆst. Das Lock ΓΆffnet sich jetzt.`; + if (res.status === 200) { + // Kein Keyholder: Entsperrcode direkt anzeigen, Lock als ungΓΌltig markiert + const data = await res.json().catch(() => ({})); + document.getElementById('emergencyModalContent').innerHTML = ` +

+ ⚠️ Das Lock wird als ungΓΌltig gewertet – + kein Historieneintrag, keine XP. +

+
+ ${data.unlockCode || '–'} +
`; + const btn = document.getElementById('btnEmergencyConfirm'); + btn.textContent = 'OK – Lock beenden'; + btn.onclick = async () => { closeEmergencyModal(); await lockLoeschen(); }; + document.getElementById('emergencyModalActions').style.display = ''; + } else if (res.status === 204) { + // Keyholder vorhanden: Benachrichtigung gesendet + const khName = _currentLock && _currentLock.keyholderName; document.getElementById('emergencyModalContent').innerHTML = - `

${successText}

`; + `

+ βœ… Notfall-Anfrage gesendet. ${khName} wurde benachrichtigt. +

`; setTimeout(() => { closeEmergencyModal(); loadLock(); }, 2000); } } catch(e) { diff --git a/xxxthegame/src/main/resources/static/js/icons.js b/xxxthegame/src/main/resources/static/js/icons.js index 0a8658d..b36b876 100644 --- a/xxxthegame/src/main/resources/static/js/icons.js +++ b/xxxthegame/src/main/resources/static/js/icons.js @@ -24,6 +24,9 @@ window.ICONS = { CHECK: { type: 'emoji', value: 'βœ…' }, DISCOVER: { type: 'emoji', value: 'πŸ—ΊοΈ' }, ARROW: { type: 'emoji', value: '▢️' }, + REFRESH: { type: 'emoji', value: 'πŸ”„' }, // Erneuern / Neu laden + START: { type: 'emoji', value: 'πŸš€' }, // Starten / Los + CELEBRATE: { type: 'emoji', value: 'πŸŽ‰' }, // Erfolg / Abschluss // ── UI-Symbole ──────────────────────────────────────────────────────── CLOSE: { type: 'symbol', value: 'βœ•' }, // Schließen / Ablehnen / LΓΆschen @@ -35,13 +38,47 @@ window.ICONS = { LIGHTNING: { type: 'emoji', value: '⚑' }, // Aktion (z. B. Zeit entfernen) EMOJI_PICKER: { type: 'emoji', value: '😊' }, // Emoji-Picker ΓΆffnen REMOVE: { type: 'symbol', value: 'βŠ—' }, // Eintrag/Spiel entfernen + EDIT: { type: 'symbol', value: '✎' }, // Bearbeiten-Button + TRASH: { type: 'emoji', value: 'πŸ—‘' }, // LΓΆschen-Button + WARNING: { type: 'emoji', value: '⚠️' }, // Warnung / Hinweis + REPORT: { type: 'symbol', value: 'βš‘' }, // Melden-Button (Flag) + VISIBILITY: { type: 'emoji', value: 'πŸ‘' }, // Sichtbar / Details sichtbar + THUMBS_UP: { type: 'emoji', value: 'πŸ‘' }, // Upvote / Zustimmung + THUMBS_DOWN: { type: 'emoji', value: 'πŸ‘Ž' }, // Downvote / Ablehnung + ARROW_UP: { type: 'symbol', value: '⬆' }, // Sortierung aufsteigend + ARROW_DOWN: { type: 'symbol', value: '⬇' }, // Sortierung absteigend + NAV_PREV: { type: 'symbol', value: '←' }, // ZurΓΌck / Vorheriges Bild + NAV_NEXT: { type: 'symbol', value: 'β†’' }, // Weiter / NΓ€chstes Bild + CAROUSEL_PREV: { type: 'symbol', value: 'β€Ή' }, // Karussell zurΓΌck + CAROUSEL_NEXT: { type: 'symbol', value: 'β€Ί' }, // Karussell weiter + TIP: { type: 'emoji', value: 'πŸ’‘' }, // Hinweis / Tipp + DOT_RED: { type: 'emoji', value: 'πŸ”΄' }, // Status-Indikator rot + COMING_SOON: { type: 'emoji', value: '🚧' }, // In Entwicklung / DemnΓ€chst // ── Chastity Game ───────────────────────────────────────────────────── NEW_LOCK: { type: 'emoji', value: 'πŸ†•' }, LOCK: { type: 'emoji', value: 'πŸ”’' }, + UNLOCK: { type: 'emoji', value: 'πŸ”“' }, // Entsperren + LOCKED_SECURE: { type: 'emoji', value: 'πŸ”' }, // Sicher gesperrt (mit SchlΓΌssel) KEY: { type: 'emoji', value: 'πŸ”‘' }, HISTORY: { type: 'emoji', value: 'πŸ”™' }, VOTES: { type: 'emoji', value: 'πŸ—³οΈ' }, + TRUST: { type: 'emoji', value: '🀝' }, // Trust-Lock + EMERGENCY: { type: 'emoji', value: 'πŸ†˜' }, // Notfall-Entsperrung + HYGIENE: { type: 'emoji', value: '🚿' }, // Hygiene-Γ–ffnung + FROZEN: { type: 'emoji', value: '❄️' }, // Eingefroren (zeitlich) + FROZEN_HARD: { type: 'emoji', value: '🧊' }, // Eingefroren (unlimitiert) + UNFREEZE: { type: 'emoji', value: '🌊' }, // Aufgetaut / Unfreeze + CODE_DIGITS: { type: 'emoji', value: 'πŸ”’' }, // Zahlenkombination / PIN-LΓ€nge + + // ── CardLock ────────────────────────────────────────────────────────── + CARD: { type: 'emoji', value: 'πŸƒ' }, // Karte (standalone) + DICE: { type: 'emoji', value: '🎲' }, // ZufΓ€llig / WΓΌrfeln + + // ── TimeLock / Spinning Wheel ────────────────────────────────────────── + SPINNING_WHEEL: { type: 'emoji', value: '🎑' }, // GlΓΌcksrad drehen + TASK_ACTIVE: { type: 'emoji', value: '🎯' }, // Aktuelle Aufgabe + CLOCK: { type: 'emoji', value: 'πŸ•' }, // Uhr / Zeitpunkt // ── Social ──────────────────────────────────────────────────────────── FEED: { type: 'emoji', value: 'πŸ“°' }, @@ -55,12 +92,34 @@ window.ICONS = { LOGOUT: { type: 'emoji', value: '⏏️' }, PROFILE: { type: 'emoji', value: 'πŸ‘€' }, HELP: { type: 'emoji', value: '❓' }, + CONTACT: { type: 'emoji', value: 'βœ‰οΈ' }, // Kontakt / E-Mail + + // ── Medien / Dateien ────────────────────────────────────────────────── + PHOTO: { type: 'emoji', value: 'πŸ“·' }, // Foto / Kamera + FILE_UPLOAD: { type: 'emoji', value: 'πŸ“' }, // Datei auswΓ€hlen / Upload + TEMPLATE: { type: 'emoji', value: 'πŸ“‹' }, // Vorlage / Template + DOCUMENT: { type: 'emoji', value: 'πŸ“„' }, // Dokument / Impressum + GUIDE: { type: 'emoji', value: 'πŸ“–' }, // Anleitung / Hilfeseite + STATS: { type: 'emoji', value: 'πŸ“Š' }, // Statistik / Umfrage-Ergebnis + PACKAGE: { type: 'emoji', value: 'πŸ“¦' }, // Paket / Einladung + MAILBOX: { type: 'emoji', value: 'πŸ“¬' }, // Posteingang (Admin) + + // ── Abo / Premium ───────────────────────────────────────────────────── + PREMIUM: { type: 'emoji', value: '⭐' }, // Abonnement / Premium + TROPHY: { type: 'emoji', value: 'πŸ†' }, // Auszeichnung / Erfolg + PAYMENT: { type: 'emoji', value: 'πŸ’³' }, // Zahlung / Abonnement + + // ── TTLock / Technik ────────────────────────────────────────────────── + MOBILE: { type: 'emoji', value: 'πŸ“±' }, // TTLock-App / MobilgerΓ€t + CONNECTION: { type: 'emoji', value: 'πŸ”Œ' }, // Verbindung / Integration + GAMEPAD: { type: 'emoji', value: 'πŸ•ΉοΈ' }, // Spielsteuerung + SHIELD: { type: 'emoji', value: 'πŸ›‘οΈ' }, // Sicherheit / Datenschutz + ADMIN_TOOLS: { type: 'emoji', value: 'πŸ”§' }, // Admin / Werkzeuge // ── Aufgaben / Items ────────────────────────────────────────────────── TOYS: { type: 'emoji', value: '➰' }, // ── Spielhistorie – Spieltypen ──────────────────────────────────────── - // Einfache Spieltypen GAME_BDSM: { type: 'emoji', value: '⛓️' }, GAME_VANILLA: { type: 'emoji', value: '❀️' }, diff --git a/xxxthegame/src/main/resources/static/keyholder.html b/xxxthegame/src/main/resources/static/keyholder.html index ca4a879..4dffb67 100644 --- a/xxxthegame/src/main/resources/static/keyholder.html +++ b/xxxthegame/src/main/resources/static/keyholder.html @@ -330,14 +330,24 @@ function esc(s) { const d = document.createElement('div'); d.textContent = s ?? ''; return d.innerHTML; } const lockDetailCache = {}; + const lockTypeMap = {}; // lockId β†’ 'CARDLOCK' | 'TIMELOCK' // ── Meine Locks als Keyholder ── async function loadLocks() { try { - const res = await fetch('/keyholder/as-keyholder'); - if (!res.ok) return; - const locks = await res.json(); + const [clRes, tlRes] = await Promise.all([ + fetch('/keyholder/as-keyholder'), + fetch('/keyholder/timelock/as-keyholder') + ]); + const cardLocks = clRes.ok ? await clRes.json() : []; + const timeLocks = tlRes.ok ? await tlRes.json() : []; + const locks = [ + ...cardLocks.map(l => ({ ...l, lockType: 'CARDLOCK' })), + ...timeLocks.map(l => ({ ...l, lockType: 'TIMELOCK' })) + ]; + locks.forEach(l => { lockTypeMap[l.lockId] = l.lockType; }); + const grid = document.getElementById('locksGrid'); grid.innerHTML = ''; const empty = document.getElementById('locksEmpty'); @@ -348,7 +358,11 @@ ? `
` : `
πŸ‘€
`; const startDate = l.startTime ? new Date(l.startTime).toLocaleDateString('de-DE') : '–'; - const frozenBadge = l.isFrozenByKeyholder ? ' Β· ❄️ Eingefroren' : ''; + const frozenBadge = (l.isFrozenByKeyholder || l.isFrozen) ? ' Β· ❄️ Eingefroren' : ''; + const emergencyBadge = l.emergencyUnlockRequested ? ' Β· πŸ†˜ Notfall!' : ''; + const line3 = l.lockType === 'TIMELOCK' + ? `⏱ TimeLock Β· seit ${startDate}${frozenBadge}${emergencyBadge}` + : `πŸƒ ${l.totalCards} Karten Β· seit ${startDate}${frozenBadge}${emergencyBadge}`; const card = document.createElement('div'); card.className = 'lock-card'; card.dataset.lockId = l.lockId; @@ -358,7 +372,7 @@
${esc(l.lockeeName)}
${esc(l.lockName)}
-
πŸƒ ${l.totalCards} Karten Β· seit ${startDate}${frozenBadge}
+
${line3}
β–Ά @@ -382,9 +396,13 @@ const card = document.querySelector(`[data-lock-id="${lockId}"]`); const body = card ? card.querySelector('.lock-detail-body') : null; try { - const res = await fetch('/keyholder/as-keyholder/' + lockId); + const endpoint = lockTypeMap[lockId] === 'TIMELOCK' + ? '/keyholder/timelock/as-keyholder/' + lockId + : '/keyholder/as-keyholder/' + lockId; + const res = await fetch(endpoint); if (!res.ok) { if (body) body.textContent = 'Fehler beim Laden.'; return; } const d = await res.json(); + lockTypeMap[lockId] = d.lockType || lockTypeMap[lockId] || 'CARDLOCK'; lockDetailCache[lockId] = d; if (body) { body.innerHTML = buildDetailHtml(d); @@ -404,7 +422,90 @@ } } + function buildTimeLockDetailHtml(d) { + let html = ``; + + // Zeitinfo + html += `
TimeLock
`; + if (d.timeUp) { + html += `
Statusβœ… Entsperrbereit
`; + } else if (d.unlockTime) { + html += `
+ Entsperrt um + ${new Date(d.unlockTime).toLocaleString('de-DE')} +
`; + } else { + html += `
EntsperrzeitNicht sichtbar
`; + } + if (d.isFrozen) { + const fu = d.frozenUntil ? new Date(d.frozenUntil).toLocaleString('de-DE') : 'unlimitiert'; + html += `
❄️ Eingefroren bis${fu}
`; + } + html += `
`; + + // Verifikation + if (d.requiresVerification) { + html += `
Verifikation heute
`; + if (!d.verificationDoneToday) { + html += `
StatusWarte auf Verifikation
`; + } else if (!d.verificationMyVote) { + html += `
+ Status + Ausstehend  PrΓΌfen β†’ +
`; + } else if (d.verificationMyVote === 'upvote') { + html += `
Statusβœ“ Erledigt
`; + } else { + html += `
Statusβœ— Abgelehnt
`; + } + html += `
`; + } + + // Gestartet am + if (d.startTime) { + html += `
+ Gestartet am ${new Date(d.startTime).toLocaleDateString('de-DE')} +
`; + } + + // Notfall-Banner + if (d.emergencyUnlockRequested && !d.keyholderRequestedUnlock) { + html += `
+ πŸ†˜ +
+
Notfall-Entsperrung angefordert!
+
Deine Lockee bittet dringend um Freigabe des Locks. Reagiere innerhalb einer Stunde oder das Lock ΓΆffnet sich automatisch.
+
+ +
+
+
`; + } + + // Lock entsperren + html += `
Lock entsperren
`; + if (d.keyholderRequestedUnlock) { + html += `
βœ… Unlock wurde angefordert – die Lockee erhΓ€lt beim nΓ€chsten Laden ihren Entsperrcode.
`; + } else { + html += `
+ +
`; + } + html += `
`; + + return html; + } + function buildDetailHtml(d) { + if (d.lockType === 'TIMELOCK') return buildTimeLockDetailHtml(d); let html = ``; @@ -1103,7 +1204,10 @@ async function requestUnlock(lockId) { try { - const res = await fetch(`/keyholder/as-keyholder/${lockId}/request-unlock`, { method: 'POST' }); + const endpoint = (lockDetailCache[lockId]?.lockType || lockTypeMap[lockId]) === 'TIMELOCK' + ? `/keyholder/timelock/as-keyholder/${lockId}/request-unlock` + : `/keyholder/as-keyholder/${lockId}/request-unlock`; + const res = await fetch(endpoint, { method: 'POST' }); if (res.ok || res.status === 204) { await reloadLockDetail(lockId); } diff --git a/xxxthegame/src/main/resources/static/meine-locks.html b/xxxthegame/src/main/resources/static/meine-locks.html index 5ee12c3..31aa780 100644 --- a/xxxthegame/src/main/resources/static/meine-locks.html +++ b/xxxthegame/src/main/resources/static/meine-locks.html @@ -175,6 +175,7 @@ display:flex; align-items:center; gap:0.5rem; background:var(--color-card); border-radius:7px; padding:0.55rem 0.75rem; flex-wrap:wrap; + border-left: 4px solid transparent; transition: border-color 0.15s; } .wheel-item select { flex:1; min-width:150px; box-sizing:border-box; @@ -650,6 +651,15 @@ { value:'TASK', label:'Aufgabe zuweisen', hasInt:false, hasStr:false }, { value:'TEXT', label:'Text anzeigen', hasInt:false, hasStr:true, strLabel:'Text' }, ]; + const WHEEL_TYPE_COLORS = { + ADD_TIME: '#f39c12', + REMOVE_TIME: '#27ae60', + FREEZE_TIME: '#3498db', + FREEZE: '#e74c3c', + UNFREEZE: '#27ae60', + TASK: '#e6b800', + TEXT: '#3498db', + }; function addWheelEntry(data) { const id = ++wheelCtr; @@ -684,8 +694,10 @@ const sel = document.querySelector(`#we-${id} select`); if (!sel) return; const def = WHEEL_TYPES.find(t => t.value === sel.value) || WHEEL_TYPES[0]; - document.getElementById('we-tp-' + id).style.display = def.hasInt ? '' : 'none'; - document.getElementById('we-str-' + id).style.display = def.hasStr ? '' : 'none'; + document.getElementById('we-tp-' + id).style.display = def.hasInt ? '' : 'none'; + document.getElementById('we-str-' + id).style.display = def.hasStr ? '' : 'none'; + const item = document.getElementById('we-' + id); + if (item) item.style.borderLeftColor = WHEEL_TYPE_COLORS[sel.value] || 'transparent'; } function removeWheelEntry(id) { document.getElementById('we-' + id)?.remove(); diff --git a/xxxthegame/src/main/resources/static/neulock.html b/xxxthegame/src/main/resources/static/neulock.html index 78e65f2..35cc53c 100644 --- a/xxxthegame/src/main/resources/static/neulock.html +++ b/xxxthegame/src/main/resources/static/neulock.html @@ -701,6 +701,38 @@ return cards; } + // ── PlausibilitΓ€tsprΓΌfung fΓΌr TimeLock ── + function validateTimeLockPlausibility(t) { + const errors = []; + const hasTasks = t.tasks && t.tasks.length > 0; + const spinEntries = t.spinningWheelEntries || []; + + // Spinning Wheel enthΓ€lt Task-Felder, aber keine Aufgaben definiert + if (spinEntries.some(e => e.type === 'TASK') && !hasTasks) { + errors.push('Das Spinning Wheel enthΓ€lt Aufgaben-Felder (TASK), aber die Vorlage hat keine Aufgaben definiert. Bitte die Vorlage bearbeiten.'); + } + + // Aufgaben-HΓ€ufigkeit konfiguriert, aber keine Aufgaben vorhanden + if ((t.taskEveryMinutes > 0 || t.minTasksPerDay > 0) && !hasTasks) { + errors.push('Aufgaben sind zeitlich konfiguriert, aber keine Aufgaben in der Vorlage definiert. Bitte die Vorlage bearbeiten.'); + } + + return errors; + } + + function showPlausibilityErrors(errors) { + const el = document.getElementById('errorMsg'); + if (errors.length === 1) { + el.textContent = errors[0]; + } else { + el.innerHTML = 'Die Vorlage enthΓ€lt inkonsistente Einstellungen:
    ' + + errors.map(e => `
  • ${e}
  • `).join('') + + '
'; + } + el.style.display = ''; + el.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + // ── Absenden ── async function createSession() { document.getElementById('errorMsg').style.display = 'none'; @@ -716,6 +748,14 @@ const t = selectedTemplate || allTemplates.find(x => x.templateId === templateId); if (!t) { showError('Vorlage nicht gefunden.'); return; } + if (t._type === 'timelock') { + const plausErrors = validateTimeLockPlausibility(t); + if (plausErrors.length > 0) { + showPlausibilityErrors(plausErrors); + return; + } + } + const lockeeVal = document.getElementById('lockeeValue').value; const keyholderVal = document.getElementById('keyholderValue').value; const isFriendLockee = lockeeVal && lockeeVal !== myUserId;