Backend: Medien-Typen, Sprachnotizen, Event-Felder und Sync-Härtung
- Event-Medien tragen Typ (image/video/audio), Dauer und Notiz; Videos bekommen ein Poster, Audio wird per ffmpeg nach AAC (audio/mp4) gewandelt, Originale werden mit Range-Unterstützung gestreamt. - Upload nimmt eine Notiz (caption) direkt mit, PATCH ändert sie später. - Neue Event-Felder: Zeitraum (end_date), Kategorie, Personen, Meilenstein. Regeln zentral in EventFields, damit CRUD und Sync gleich prüfen. - Titel darf leer sein: ein Event entsteht mit dem ersten Eintrag. - Artisan-Befehl media:transcode-voice-notes wandelt alte WebM/Ogg-Notizen, die Safari nicht abspielen kann. - Login-Throttling, Settings-Validierung, Sync-Fehlercodes ohne Rohtext. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
f79dcb9928
commit
b262a6771f
59 changed files with 11879 additions and 197 deletions
|
|
@ -6,6 +6,19 @@ use Illuminate\Foundation\Http\FormRequest;
|
|||
|
||||
class StoreEventMediaRequest extends FormRequest
|
||||
{
|
||||
/** Images accepted everywhere an image is allowed. */
|
||||
private const IMAGE_MIMES = 'jpg,jpeg,png,webp';
|
||||
|
||||
/** Container formats phones and browsers actually produce. */
|
||||
private const VIDEO_MIMETYPES = 'video/mp4,video/quicktime,video/webm,video/x-m4v';
|
||||
|
||||
/**
|
||||
* MediaRecorder output differs per browser: Chrome and Firefox record
|
||||
* audio into a WebM container, which libmagic reports as video/webm;
|
||||
* Safari records audio/mp4 (often sniffed as audio/x-m4a or video/mp4).
|
||||
*/
|
||||
private const AUDIO_MIMETYPES = 'audio/webm,video/webm,audio/ogg,application/ogg,audio/mp4,audio/x-m4a,video/mp4,audio/mpeg,audio/wav,audio/x-wav,audio/aac';
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
|
|
@ -14,13 +27,44 @@ class StoreEventMediaRequest extends FormRequest
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* The accepted file type depends on the collection: the key image stays
|
||||
* an image, the gallery takes images and videos, and a voice note is
|
||||
* audio only.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$file = match ($this->input('collection', 'gallery')) {
|
||||
'voice_note' => ['required', 'file', 'mimetypes:'.self::AUDIO_MIMETYPES, 'max:20480'],
|
||||
'gallery' => [
|
||||
'required',
|
||||
'file',
|
||||
'mimetypes:image/jpeg,image/png,image/webp,'.self::VIDEO_MIMETYPES,
|
||||
'max:102400',
|
||||
],
|
||||
default => ['required', 'image', 'mimes:'.self::IMAGE_MIMES, 'max:10240'],
|
||||
};
|
||||
|
||||
return [
|
||||
'file' => ['required', 'image', 'mimes:jpg,jpeg,png,webp', 'max:10240'],
|
||||
'collection' => ['nullable', 'in:key_image,gallery'],
|
||||
'file' => $file,
|
||||
'collection' => ['nullable', 'in:key_image,gallery,voice_note'],
|
||||
// Sent along with the file when the note was written before the
|
||||
// upload could happen (offline), so it needs no second request.
|
||||
'caption' => ['nullable', 'string', 'max:500'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'file.mimetypes' => 'Dieses Dateiformat wird hier nicht unterstützt.',
|
||||
'file.mimes' => 'Dieses Dateiformat wird hier nicht unterstützt.',
|
||||
'file.image' => 'Für das Key Image ist nur ein Bild erlaubt.',
|
||||
'file.max' => 'Die Datei ist zu groß.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue