refactor: Remove ALTCHA completely for simple 1-click guest signups
This commit is contained in:
Binary file not shown.
@@ -346,13 +346,6 @@ class ShiftSignupView(views.APIView):
|
|||||||
if not guest_name:
|
if not guest_name:
|
||||||
return Response({'error': 'Bitte gib einen Namen an.'}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': 'Bitte gib einen Namen an.'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
captcha_token = request.data.get('captcha_token', '').strip()
|
|
||||||
if not captcha_token and not is_manager:
|
|
||||||
return Response({'error': 'Bitte schließe zuerst den ALTCHA Spamschutz ab.'}, status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
if not is_manager and not verify_altcha_payload(captcha_token):
|
|
||||||
return Response({'error': 'ALTCHA Verifizierung ungültig. Bitte versuche es erneut.'}, status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
# If NOT a manager, enforce required skills check for guest signups
|
# If NOT a manager, enforce required skills check for guest signups
|
||||||
if not is_manager and shift.required_skills.exists():
|
if not is_manager and shift.required_skills.exists():
|
||||||
required_names = ", ".join([s.name for s in shift.required_skills.all()])
|
required_names = ", ".join([s.name for s in shift.required_skills.all()])
|
||||||
|
|||||||
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -11,8 +11,8 @@
|
|||||||
<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-g0sgtMk-.js"></script>
|
<script type="module" crossorigin src="/assets/index-udMfIy9d.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-fTGRNVay.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-B6pC8vGA.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">
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,22 +1,10 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { X, ShieldCheck, UserCheck, AlertCircle, CheckCircle2 } from 'lucide-react';
|
import { X, UserCheck, AlertCircle } from 'lucide-react';
|
||||||
import 'altcha';
|
|
||||||
import 'altcha/altcha.css';
|
|
||||||
|
|
||||||
export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
||||||
const [guestName, setGuestName] = useState('');
|
const [guestName, setGuestName] = useState('');
|
||||||
const [sessionVerified, setSessionVerified] = useState(() => {
|
|
||||||
return sessionStorage.getItem('guest_captcha_verified') === 'true';
|
|
||||||
});
|
|
||||||
const [captchaToken, setCaptchaToken] = useState(() => {
|
|
||||||
return sessionStorage.getItem('guest_captcha_verified') === 'true' ? 'altcha-session-verified' : '';
|
|
||||||
});
|
|
||||||
const [isCaptchaSolved, setIsCaptchaSolved] = useState(() => {
|
|
||||||
return sessionStorage.getItem('guest_captcha_verified') === 'true';
|
|
||||||
});
|
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const captchaRef = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Load saved guest name from localStorage
|
// Load saved guest name from localStorage
|
||||||
@@ -26,39 +14,6 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (sessionVerified) return;
|
|
||||||
|
|
||||||
const el = captchaRef.current;
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
const handleStateChange = (e) => {
|
|
||||||
const state = e?.detail?.state;
|
|
||||||
const payload = e?.detail?.payload;
|
|
||||||
if (state === 'verified' || e?.detail?.verified) {
|
|
||||||
sessionStorage.setItem('guest_captcha_verified', 'true');
|
|
||||||
setSessionVerified(true);
|
|
||||||
setIsCaptchaSolved(true);
|
|
||||||
setCaptchaToken(payload || ('altcha-verified-' + Math.random().toString(36).substring(2, 10)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
el.addEventListener('statechange', handleStateChange);
|
|
||||||
el.addEventListener('verified', handleStateChange);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
el.removeEventListener('statechange', handleStateChange);
|
|
||||||
el.removeEventListener('verified', handleStateChange);
|
|
||||||
};
|
|
||||||
}, [sessionVerified]);
|
|
||||||
|
|
||||||
const handleManualVerify = () => {
|
|
||||||
sessionStorage.setItem('guest_captcha_verified', 'true');
|
|
||||||
setSessionVerified(true);
|
|
||||||
setIsCaptchaSolved(true);
|
|
||||||
setCaptchaToken('altcha-verified-' + Math.random().toString(36).substring(2, 10));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setError('');
|
setError('');
|
||||||
@@ -68,22 +23,13 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isVerified = sessionVerified || isCaptchaSolved;
|
|
||||||
|
|
||||||
if (!isVerified) {
|
|
||||||
setError('Bitte schließe zuerst den ALTCHA Security Check ab.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = captchaToken || 'altcha-session-verified';
|
|
||||||
|
|
||||||
// Save in localStorage for guest convenience
|
// Save in localStorage for guest convenience
|
||||||
localStorage.setItem('guest_display_name', guestName.trim());
|
localStorage.setItem('guest_display_name', guestName.trim());
|
||||||
window.dispatchEvent(new Event('guest_name_updated'));
|
window.dispatchEvent(new Event('guest_name_updated'));
|
||||||
|
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await onSubmit({ guest_name: guestName.trim(), captcha_token: token });
|
await onSubmit({ guest_name: guestName.trim() });
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err.message || 'Eintragen fehlgeschlagen.');
|
setError(err.message || 'Eintragen fehlgeschlagen.');
|
||||||
@@ -137,59 +83,6 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ALTCHA Security Check Section */}
|
|
||||||
{sessionVerified ? (
|
|
||||||
<div className="p-3.5 rounded-xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs flex items-center justify-between font-mono">
|
|
||||||
<span className="flex items-center gap-2 font-semibold">
|
|
||||||
<CheckCircle2 className="w-4 h-4 text-emerald-400 shrink-0" /> ALTCHA Spamschutz verifiziert
|
|
||||||
</span>
|
|
||||||
<span className="text-[10px] text-emerald-400/80">[ In dieser Sitzung aktiv ]</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="p-4 rounded-xl bg-slate-900/90 border border-slate-800 space-y-3">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<span className="text-xs font-semibold text-slate-300 flex items-center gap-1.5 font-mono">
|
|
||||||
<ShieldCheck className="w-4 h-4 text-emerald-400" /> Security Check (ALTCHA)
|
|
||||||
</span>
|
|
||||||
<a
|
|
||||||
href="https://altcha.org/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="text-[10px] text-blue-400 hover:underline font-mono"
|
|
||||||
>
|
|
||||||
ALTCHA.org
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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
|
|
||||||
ref={captchaRef}
|
|
||||||
challengeurl="/api/altcha-challenge/"
|
|
||||||
test="true"
|
|
||||||
auto="onload"
|
|
||||||
hidefooter="true"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
></altcha-widget>
|
|
||||||
|
|
||||||
{!isCaptchaSolved && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={handleManualVerify}
|
|
||||||
className="text-xs font-mono px-3 py-1.5 rounded-lg bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 hover:bg-emerald-500/30 transition flex items-center gap-1.5 mt-1"
|
|
||||||
>
|
|
||||||
<CheckCircle2 className="w-3.5 h-3.5" /> Security Check bestätigen
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isCaptchaSolved && (
|
|
||||||
<div className="mt-2 text-xs font-medium text-emerald-400 flex items-center gap-1 font-mono">
|
|
||||||
<CheckCircle2 className="w-4 h-4" /> ALTCHA erfolgreich verifiziert!
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="pt-2 flex justify-end gap-2">
|
<div className="pt-2 flex justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
Reference in New Issue
Block a user