This commit is contained in:
Saufi
2026-06-02 17:35:45 +08:00
commit 4ef99b1f81
148 changed files with 21134 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
class CreateUserRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->isAdmin();
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
'password' => ['required', 'confirmed', Password::min(8)->mixedCase()->numbers()],
'role' => ['required', 'in:admin,user'],
'department_id' => ['nullable', 'exists:departments,id'],
];
}
public function attributes(): array
{
return [
'name' => 'Nama',
'email' => 'E-mel',
'password' => 'Kata laluan',
'role' => 'Peranan',
'department_id' => 'Jabatan',
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class TransferOwnershipRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->isAdmin();
}
public function rules(): array
{
return [
'new_owner_id' => ['required', 'integer', 'exists:users,id'],
'justification' => ['required', 'string', 'min:10', 'max:1000'],
];
}
public function attributes(): array
{
return [
'new_owner_id' => 'Pemilik baru',
'justification' => 'Justifikasi',
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateUserEmailRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->isAdmin();
}
public function rules(): array
{
$userId = $this->route('user')->id;
return [
'email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')->ignore($userId)],
'justification'=> ['nullable', 'string', 'max:500'],
];
}
public function attributes(): array
{
return [
'email' => 'E-mel baru',
'justification' => 'Justifikasi',
];
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Auth\Events\Lockout;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class LoginRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string'],
];
}
public function authenticate(): void
{
$this->ensureIsNotRateLimited();
if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
public function ensureIsNotRateLimited(): void
{
if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
return;
}
event(new Lockout($this));
$seconds = RateLimiter::availableIn($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.throttle', [
'seconds' => $seconds,
'minutes' => ceil($seconds / 60),
]),
]);
}
public function throttleKey(): string
{
return Str::transliterate(Str::lower($this->string('email')) . '|' . $this->ip());
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Http\Requests\User;
use App\Rules\ValidAudioMagicBytes;
use Illuminate\Foundation\Http\FormRequest;
class CreateProjectRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->isActive();
}
public function rules(): array
{
$maxKb = config('speech2text.upload.max_mb', 200) * 1024;
$extensions = implode(',', config('speech2text.upload.allowed_extensions'));
return [
'title' => ['required', 'string', 'max:255'],
'description' => ['nullable', 'string', 'max:2000'],
'audio' => [
'required',
'file',
"mimes:{$extensions}",
"max:{$maxKb}",
new ValidAudioMagicBytes(),
],
'language' => ['nullable', 'string', 'in:ms,en'],
];
}
public function attributes(): array
{
return [
'title' => 'Tajuk projek',
'description' => 'Penerangan',
'audio' => 'Fail audio',
'language' => 'Bahasa',
];
}
public function messages(): array
{
$maxMb = config('speech2text.upload.max_mb', 200);
return [
'audio.max' => "Saiz fail audio melebihi had maksimum {$maxMb}MB.",
'audio.mimes' => 'Format fail tidak disokong. Guna: mp3, wav, m4a, mp4, aac, ogg, flac, webm.',
];
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class StoreCommentRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'message' => ['required', 'string', 'max:2000'],
];
}
public function messages(): array
{
return [
'message.required' => 'Mesej komen tidak boleh kosong.',
'message.max' => 'Mesej terlalu panjang (maks 2,000 aksara).',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class UpdateTranscriptRequest extends FormRequest
{
public function authorize(): bool
{
return true; // Policy diperiksa dalam controller
}
public function rules(): array
{
return [
'transcript_text' => ['required', 'string', 'max:500000'],
'change_summary' => ['nullable', 'string', 'max:500'],
];
}
public function messages(): array
{
return [
'transcript_text.required' => 'Teks transkripsi tidak boleh kosong.',
'transcript_text.max' => 'Teks transkripsi terlalu panjang (maks 500,000 aksara).',
'change_summary.max' => 'Ringkasan perubahan terlalu panjang (maks 500 aksara).',
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class UploadExternalTranscriptRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'transcript_file' => ['required', 'file', 'mimetypes:text/plain', 'extensions:txt', 'max:10240'],
'clean_with_ollama' => ['nullable', 'boolean'],
'confirmed' => ['nullable', 'boolean'],
];
}
public function messages(): array
{
return [
'transcript_file.required' => 'Sila pilih fail transkripsi (.txt).',
'transcript_file.mimetypes' => 'Fail mesti berformat teks biasa (.txt).',
'transcript_file.extensions'=> 'Hanya fail .txt dibenarkan.',
'transcript_file.max' => 'Saiz fail terlalu besar (maks 10 MB).',
];
}
}