fix: Register /api/altcha-challenge/ route and return real display_name for own guest session signups
This commit is contained in:
Binary file not shown.
@@ -13,24 +13,48 @@ class SkillSerializer(serializers.ModelSerializer):
|
|||||||
class ShiftSignupSerializer(serializers.ModelSerializer):
|
class ShiftSignupSerializer(serializers.ModelSerializer):
|
||||||
display_name = serializers.SerializerMethodField()
|
display_name = serializers.SerializerMethodField()
|
||||||
is_guest = serializers.SerializerMethodField()
|
is_guest = serializers.SerializerMethodField()
|
||||||
|
is_self = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ShiftSignup
|
model = ShiftSignup
|
||||||
fields = ['id', 'display_name', 'is_guest', 'created_at']
|
fields = ['id', 'display_name', 'is_guest', 'is_self', 'created_at']
|
||||||
|
|
||||||
def get_is_guest(self, obj):
|
def get_is_guest(self, obj):
|
||||||
return obj.user is None
|
return obj.user is None
|
||||||
|
|
||||||
|
def _is_own_signup(self, obj, request):
|
||||||
|
if not request:
|
||||||
|
return False
|
||||||
|
if request.user and request.user.is_authenticated:
|
||||||
|
return obj.user_id == request.user.id
|
||||||
|
|
||||||
|
# Check session key for guest user
|
||||||
|
session_key = getattr(request.session, 'session_key', None)
|
||||||
|
if session_key and obj.guest_session_key and obj.guest_session_key == session_key:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_is_self(self, obj):
|
||||||
|
request = self.context.get('request')
|
||||||
|
return self._is_own_signup(obj, request)
|
||||||
|
|
||||||
def get_display_name(self, obj):
|
def get_display_name(self, obj):
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
# PRIVACY RULE: Guests (unauthenticated users) MUST NOT see who signed up where
|
|
||||||
if request and not request.user.is_authenticated:
|
|
||||||
return "Belegt (Anonym)"
|
|
||||||
|
|
||||||
|
# Authenticated users see real names of all participants
|
||||||
|
if request and request.user and request.user.is_authenticated:
|
||||||
if obj.user:
|
if obj.user:
|
||||||
return obj.user.get_display_name()
|
return obj.user.get_display_name()
|
||||||
return obj.guest_name or "Gast"
|
return obj.guest_name or "Gast"
|
||||||
|
|
||||||
|
# Guest users see their own real name for their own signups
|
||||||
|
if request and self._is_own_signup(obj, request):
|
||||||
|
return obj.guest_name or "Gast"
|
||||||
|
|
||||||
|
# Other participants are anonymized for privacy
|
||||||
|
return "Belegt (Anonym)"
|
||||||
|
|
||||||
class ShiftSerializer(serializers.ModelSerializer):
|
class ShiftSerializer(serializers.ModelSerializer):
|
||||||
required_skills = SkillSerializer(many=True, read_only=True)
|
required_skills = SkillSerializer(many=True, read_only=True)
|
||||||
required_skill_ids = serializers.PrimaryKeyRelatedField(
|
required_skill_ids = serializers.PrimaryKeyRelatedField(
|
||||||
|
|||||||
Binary file not shown.
@@ -1,8 +1,11 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
from apps.events.views import AltchaChallengeView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
path('api/altcha-challenge/', AltchaChallengeView.as_view(), name='altcha-challenge-top'),
|
||||||
|
path('api/events/altcha-challenge/', AltchaChallengeView.as_view(), name='altcha-challenge-alias'),
|
||||||
path('api/users/', include('apps.users.urls')),
|
path('api/users/', include('apps.users.urls')),
|
||||||
path('api/', include('apps.events.urls')),
|
path('api/', include('apps.events.urls')),
|
||||||
path('api/branding/', include('apps.branding.urls')),
|
path('api/branding/', include('apps.branding.urls')),
|
||||||
|
|||||||
+9
-9
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
<title>Schichtplaner — Veranstaltungsschichtpläne</title>
|
<title>Schichtplaner — Veranstaltungsschichtpläne</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BzMPGQ3H.js"></script>
|
<script type="module" crossorigin src="/assets/index-5XQR3AzF.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-fTGRNVay.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-fTGRNVay.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-paper text-main font-sans antialiased min-h-screen">
|
<body class="bg-paper text-main font-sans antialiased min-h-screen">
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
|||||||
<div className="border border-slate-700 rounded-lg p-3 bg-slate-950/80 flex flex-col items-center justify-center min-h-[90px] gap-2">
|
<div className="border border-slate-700 rounded-lg p-3 bg-slate-950/80 flex flex-col items-center justify-center min-h-[90px] gap-2">
|
||||||
<altcha-widget
|
<altcha-widget
|
||||||
ref={captchaRef}
|
ref={captchaRef}
|
||||||
challengeurl="/api/events/altcha-challenge/"
|
challengeurl="/api/altcha-challenge/"
|
||||||
auto="onload"
|
auto="onload"
|
||||||
hidefooter="true"
|
hidefooter="true"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ export default function ShiftMatrixTable({
|
|||||||
{/* Attendees List */}
|
{/* Attendees List */}
|
||||||
<div className="mt-2 space-y-1 font-sans">
|
<div className="mt-2 space-y-1 font-sans">
|
||||||
{shift.signups.map((su) => {
|
{shift.signups.map((su) => {
|
||||||
const isOwnGuest = isGuest && su.is_guest && guestDisplayName && su.display_name?.trim().toLowerCase() === guestDisplayName.trim().toLowerCase();
|
const isOwnGuest = isGuest && su.is_guest && (su.is_self || (guestDisplayName && su.display_name?.trim().toLowerCase() === guestDisplayName.trim().toLowerCase()));
|
||||||
return (
|
return (
|
||||||
<div key={su.id} className={`text-[11px] text-muted flex items-center justify-between gap-2 p-1.5 rounded-sm border ${isOwnGuest ? 'bg-amber-500/10 border-amber-500/30' : 'bg-subtle border-grid'}`}>
|
<div key={su.id} className={`text-[11px] text-muted flex items-center justify-between gap-2 p-1.5 rounded-sm border ${isOwnGuest ? 'bg-amber-500/10 border-amber-500/30' : 'bg-subtle border-grid'}`}>
|
||||||
<div className="flex items-center gap-1.5 truncate">
|
<div className="flex items-center gap-1.5 truncate">
|
||||||
|
|||||||
Reference in New Issue
Block a user