big update base struktur tahap 1

This commit is contained in:
Wian Drs
2026-07-27 16:24:09 +07:00
parent 2b3592c4c2
commit 1dd02baa72
169 changed files with 24405 additions and 977 deletions
@@ -23,33 +23,48 @@ class AuditLogFilterRequest extends FormRequest
public function rules(): array
{
return [
/** Filter berdasarkan nama modul audit. */
'module' => [
'nullable',
'string'
'string',
'max:100',
],
/** Filter berdasarkan nama action audit. */
'action' => [
'nullable',
'string'
'string',
'max:100',
],
/** Filter berdasarkan ID user pelaku. */
'user_id' => [
'nullable',
'integer'
'integer',
'exists:users,id',
],
/** Filter berdasarkan ID tenant. */
'tenant_id' => [
'nullable',
'integer'
'integer',
'exists:tenants,id',
],
/** Nomor halaman yang ingin diambil. */
'page' => [
'nullable',
'integer',
'min:1',
],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => [
'nullable',
'integer',
'min:1',
'max:100'
]
'max:100',
],
];
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class RegisterRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:100'],
'username' => ['nullable', 'string', 'max:50', 'unique:users,username'],
'email' => ['required', 'email', 'max:100', 'unique:users,email'],
'whatsapp_number' => ['required', 'string', 'max:20'],
'password' => ['required', 'string', 'min:8', 'max:100'],
'verification_channel' => ['required', Rule::in(['email', 'whatsapp'])],
'verification_target' => ['required', 'string', 'max:100'],
];
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class ResendVerificationCodeRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'verification_channel' => ['required', Rule::in(['email', 'whatsapp'])],
'verification_target' => ['required', 'string', 'max:100'],
];
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class VerifyRegistrationRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'verification_channel' => ['required', Rule::in(['email', 'whatsapp'])],
'verification_target' => ['required', 'string', 'max:100'],
'verification_code' => ['required', 'digits:6'],
];
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Http\Requests\File;
use Illuminate\Foundation\Http\FormRequest;
class IndexStoredFileRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'category' => ['nullable', 'string', 'max:80'],
'mime_type' => ['nullable', 'string', 'max:150'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\File;
use Illuminate\Foundation\Http\FormRequest;
class StoreFileRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'file' => [
'required',
'file',
'max:20480',
'mimes:jpg,jpeg,png,webp,gif,pdf,doc,docx,xls,xlsx,csv,txt,zip',
],
'category' => ['nullable', 'string', 'max:80', 'regex:/^[a-z0-9_-]+$/'],
];
}
public function messages(): array
{
return [
'file.max' => 'Ukuran file maksimal 20 MB.',
'file.mimes' => 'Jenis file tidak didukung.',
'category.regex' => 'Kategori hanya boleh berisi huruf kecil, angka, garis bawah, atau tanda hubung.',
];
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Material;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexMaterialRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari barcode atau nama material. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter material berdasarkan ID user/teknisi. */
'user_id' => ['nullable', 'integer', 'exists:users,id'],
/** Filter jenis material. */
'type' => ['nullable', Rule::in(['serialized', 'consumable'])],
/** Filter status material. */
'status' => ['nullable', 'string', 'max:50'],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\MenuGroup;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexMenuGroupRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari nama atau deskripsi menu group. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter status aktif menu group. */
'is_active' => ['nullable', 'boolean'],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
/** Kolom pengurutan data. */
'sort_by' => ['nullable', Rule::in(['id', 'name', 'description', 'is_active', 'is_system', 'created_at'])],
/** Arah pengurutan data. */
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,62 @@
<?php
namespace App\Http\Requests\MenuGroup;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreMenuGroupRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$isMaster = $this->user()?->isMasterAdmin() ?? false;
$tenantId = $isMaster
? $this->input('tenant_id')
: $this->attributes->get('tenant_id');
return [
'tenant_id' => [
$isMaster ? 'nullable' : 'prohibited',
'integer',
'exists:tenants,id',
],
'name' => [
'required',
'string',
'max:100',
Rule::unique('menu_groups', 'name')
->where(fn ($query) => $tenantId
? $query->where('tenant_id', $tenantId)
: $query->whereNull('tenant_id')),
],
'description' => [
'nullable',
'string',
],
'is_active' => [
'nullable',
'boolean',
],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'is_active' => filter_var(
$this->is_active,
FILTER_VALIDATE_BOOLEAN,
FILTER_NULL_ON_FAILURE
),
]);
}
}
@@ -0,0 +1,58 @@
<?php
namespace App\Http\Requests\MenuGroup;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class SyncMenuGroupMenusRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'menus' => [
'required',
'array',
'min:1',
],
'menus.*.menu_id' => [
'required',
'integer',
'distinct',
'exists:menu_lists,id',
],
'menus.*.can_view' => [
'nullable',
'boolean',
],
'menus.*.can_create' => [
'nullable',
'boolean',
],
'menus.*.can_update' => [
'nullable',
'boolean',
],
'menus.*.can_delete' => [
'nullable',
'boolean',
],
'menus.*.can_approve' => [
'nullable',
'boolean',
],
'menus.*.can_export' => [
'nullable',
'boolean',
],
];
}
}
@@ -0,0 +1,61 @@
<?php
namespace App\Http\Requests\MenuGroup;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class SyncUserMenuGroupsRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'assignments' => [
'required',
'array',
'min:1',
],
'assignments.*.menu_group_id' => [
'required',
'integer',
'exists:menu_groups,id',
],
'assignments.*.tenant_id' => [
'nullable',
'integer',
'exists:tenants,id',
],
];
}
public function withValidator($validator): void
{
$validator->after(function ($validator) {
$assignments = $this->input('assignments', []);
$seen = [];
foreach ($assignments as $index => $assignment) {
$menuGroupId = $assignment['menu_group_id'] ?? null;
$tenantId = $assignment['tenant_id'] ?? null;
$key = $menuGroupId.'|'.($tenantId ?? 'null');
if (isset($seen[$key])) {
$validator->errors()->add(
"assignments.$index",
'Kombinasi menu_group_id dan tenant_id harus unik.'
);
}
$seen[$key] = true;
}
});
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Http\Requests\MenuGroup;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateMenuGroupRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$menuGroupId = $this->route('menu_group')?->id;
$isMaster = $this->user()?->isMasterAdmin() ?? false;
$tenantId = $isMaster
? ($this->exists('tenant_id')
? $this->input('tenant_id')
: $this->route('menu_group')?->tenant_id)
: $this->route('menu_group')?->tenant_id;
return [
'tenant_id' => [
$isMaster ? 'nullable' : 'prohibited',
'integer',
'exists:tenants,id',
],
'name' => [
'required',
'string',
'max:100',
Rule::unique('menu_groups', 'name')
->where(fn ($query) => $tenantId
? $query->where('tenant_id', $tenantId)
: $query->whereNull('tenant_id'))
->ignore($menuGroupId),
],
'description' => [
'nullable',
'string',
],
'is_active' => [
'nullable',
'boolean',
],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'is_active' => filter_var(
$this->is_active,
FILTER_VALIDATE_BOOLEAN,
FILTER_NULL_ON_FAILURE
),
]);
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Requests\MenuList;
use Illuminate\Foundation\Http\FormRequest;
class IndexMenuListRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari nama, slug, atau URL menu. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter status aktif menu. */
'is_active' => ['nullable', 'boolean'],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,81 @@
<?php
namespace App\Http\Requests\MenuList;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreMenuListRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'parent_id' => [
'nullable',
'integer',
Rule::exists('menu_lists', 'id'),
],
'name' => [
'required',
'string',
'max:255',
],
'slug' => [
'required',
'string',
'max:255',
'unique:menu_lists,slug',
],
'url' => [
'nullable',
'string',
'max:255',
],
'icon' => [
'nullable',
'string',
'max:255',
],
'component' => [
'nullable',
'string',
'max:255',
],
'sort_order' => [
'nullable',
'integer',
'min:0',
],
'is_active' => [
'nullable',
'boolean',
],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'is_active' => filter_var(
$this->is_active,
FILTER_VALIDATE_BOOLEAN
),
]);
}
}
@@ -0,0 +1,83 @@
<?php
namespace App\Http\Requests\MenuList;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateMenuListRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'parent_id' => [
'nullable',
'integer',
Rule::exists('menu_lists', 'id'),
'different:menu_list.id',
],
'name' => [
'required',
'string',
'max:255',
],
'slug' => [
'required',
'string',
'max:255',
Rule::unique('menu_lists', 'slug')
->ignore($this->menu_list->id),
],
'url' => [
'nullable',
'string',
'max:255',
],
'icon' => [
'nullable',
'string',
'max:255',
],
'component' => [
'nullable',
'string',
'max:255',
],
'sort_order' => [
'nullable',
'integer',
'min:0',
],
'is_active' => [
'nullable',
'boolean',
],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'is_active' => filter_var(
$this->is_active,
FILTER_VALIDATE_BOOLEAN
),
]);
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\Nas;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexNasResourceRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'status' => ['nullable', Rule::in(['active', 'inactive'])],
'connection_type' => ['nullable', Rule::in(['api', 'radius'])],
'service_type' => ['nullable', Rule::in(['ppp', 'hotspot', 'radius'])],
'page' => ['nullable', 'integer', 'min:1'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
'sort_by' => ['nullable', Rule::in(['id', 'name', 'host', 'connection_type', 'service_type', 'vendor', 'device_type', 'status', 'created_at'])],
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,75 @@
<?php
namespace App\Http\Requests\Nas;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreNasResourceRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return array_merge($this->commonRules(), match ($this->route()->defaults['nas_resource'] ?? null) {
'mikrotik' => [
'connection_type' => ['required', Rule::in(['api', 'radius'])],
'host' => ['required', 'string', 'max:255'],
'api_port' => ['nullable', 'integer', 'between:1,65535'],
'api_username' => ['nullable', 'string', 'max:255'],
'api_password' => ['nullable', 'string', 'max:1000'],
'radius_auth_port' => ['nullable', 'integer', 'between:1,65535'],
'radius_accounting_port' => ['nullable', 'integer', 'between:1,65535'],
'radius_secret' => ['nullable', 'string', 'max:1000'],
'timeout' => ['nullable', 'integer', 'between:1,300'],
],
'package-profile' => [
'service_type' => ['required', Rule::in(['ppp', 'hotspot', 'radius'])],
'external_profile_name' => ['nullable', 'string', 'max:255'],
'download_kbps' => ['nullable', 'integer', 'min:0'],
'upload_kbps' => ['nullable', 'integer', 'min:0'],
'local_address' => ['nullable', 'string', 'max:255'],
'remote_address_pool' => ['nullable', 'string', 'max:255'],
'session_timeout' => ['nullable', 'integer', 'min:0'],
'idle_timeout' => ['nullable', 'integer', 'min:0'],
'shared_users' => ['nullable', 'integer', 'min:1'],
'price' => ['nullable', 'numeric', 'min:0'],
],
'olt' => [
'vendor' => ['nullable', 'string', 'max:255'],
'model' => ['nullable', 'string', 'max:255'],
'host' => ['required', 'string', 'max:255'],
'snmp_port' => ['nullable', 'integer', 'between:1,65535'],
'snmp_version' => ['required', Rule::in(['v1', 'v2c', 'v3'])],
'community' => ['nullable', 'string', 'max:1000'],
'security_level' => ['nullable', Rule::in(['noAuthNoPriv', 'authNoPriv', 'authPriv'])],
'security_name' => ['nullable', 'string', 'max:255'],
'auth_protocol' => ['nullable', Rule::in(['MD5', 'SHA', 'SHA224', 'SHA256', 'SHA384', 'SHA512'])],
'auth_password' => ['nullable', 'string', 'max:1000'],
'privacy_protocol' => ['nullable', Rule::in(['DES', 'AES', 'AES192', 'AES256'])],
'privacy_password' => ['nullable', 'string', 'max:1000'],
'timeout' => ['nullable', 'integer', 'between:1,300'],
],
'webfig' => [
'device_type' => ['nullable', 'string', 'max:100'],
'url' => ['required', 'url:http,https', 'max:2000'],
'username' => ['nullable', 'string', 'max:255'],
'password' => ['nullable', 'string', 'max:1000'],
],
default => [],
});
}
protected function commonRules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'name' => ['required', 'string', 'max:255'],
'status' => ['nullable', Rule::in(['active', 'inactive'])],
'notes' => ['nullable', 'string'],
];
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Requests\Nas;
class UpdateNasResourceRequest extends StoreNasResourceRequest
{
public function rules(): array
{
return collect(parent::rules())
->map(function ($rules) {
$rules = is_array($rules) ? $rules : [$rules];
if (($index = array_search('required', $rules, true)) !== false) {
$rules[$index] = 'sometimes';
}
return $rules;
})
->all();
}
}
@@ -0,0 +1,95 @@
<?php
namespace App\Http\Requests\Profile;
use App\Models\StoredFile;
use App\Services\File\StoredFileService;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class UpdateProfileRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
$userId = $this->user()->id;
return [
'name' => ['required', 'string', 'max:255'],
'username' => [
'nullable',
'string',
'max:255',
Rule::unique('users', 'username')->ignore($userId),
],
'email' => [
'required',
'email',
'max:255',
Rule::unique('users', 'email')->ignore($userId),
],
'whatsapp_number' => ['nullable', 'string', 'max:20'],
'profile_photo_file_id' => ['nullable', 'integer', 'exists:stored_files,id'],
'current_password' => ['nullable', 'required_with:password', 'string'],
'password' => ['nullable', 'string', 'min:8', 'confirmed'],
'user_profile' => ['nullable', 'array'],
'user_profile.nik' => ['nullable', 'string', 'max:30'],
'user_profile.address' => ['nullable', 'string'],
'user_profile.provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
'user_profile.kabupaten_id' => [
'nullable',
'integer',
Rule::exists('wilayah_kabupaten', 'id')->where(
'provinsi_id',
$this->input('user_profile.provinsi_id')
),
],
'user_profile.kecamatan_id' => [
'nullable',
'integer',
Rule::exists('wilayah_kecamatan', 'id')->where(
'kabupaten_id',
$this->input('user_profile.kabupaten_id')
),
],
'user_profile.desa_id' => [
'nullable',
'integer',
Rule::exists('wilayah_desa', 'id')->where(
'kecamatan_id',
$this->input('user_profile.kecamatan_id')
),
],
];
}
public function after(): array
{
return [
function (Validator $validator) {
if ($this->filled('password')
&& ! Hash::check((string) $this->input('current_password'), $this->user()->password)) {
$validator->errors()->add(
'current_password',
'Password saat ini tidak sesuai.'
);
}
if ($this->filled('profile_photo_file_id')) {
$file = StoredFile::find($this->integer('profile_photo_file_id'));
if ($file) {
app(StoredFileService::class)->validateProfilePhoto($file, $this->user());
}
}
},
];
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Tenant;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexTenantRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari kode, nama, atau email tenant. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter status tenant. */
'status' => ['nullable', Rule::in(['active', 'inactive'])],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
/** Kolom pengurutan data. */
'sort_by' => ['nullable', Rule::in(['id', 'tenant_code', 'tenant_name', 'email', 'status', 'created_at'])],
/** Arah pengurutan data. */
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,52 @@
<?php
namespace App\Http\Requests\Tenant;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class StoreTenantRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'tenant_code' => [
'required',
'string',
'max:100',
'unique:tenants,tenant_code',
],
'tenant_name' => [
'required',
'string',
'max:255',
],
'phone' => [
'nullable',
'string',
'max:50',
],
'email' => [
'nullable',
'email',
'max:255',
],
'address' => [
'nullable',
'string',
],
'status' => [
'nullable',
'in:active,inactive',
],
];
}
}
@@ -0,0 +1,58 @@
<?php
namespace App\Http\Requests\Tenant;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateTenantRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$tenantId = $this->route('tenant')?->id;
return [
'tenant_code' => [
'sometimes',
'required',
'string',
'max:100',
Rule::unique('tenants', 'tenant_code')->ignore($tenantId),
],
'tenant_name' => [
'sometimes',
'required',
'string',
'max:255',
],
'phone' => [
'nullable',
'string',
'max:50',
],
'email' => [
'nullable',
'email',
'max:255',
],
'address' => [
'nullable',
'string',
],
'status' => [
'sometimes',
'required',
'in:active,inactive',
],
];
}
}
@@ -0,0 +1,37 @@
<?php
namespace App\Http\Requests\Ticket;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexTicketRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari nomor, judul, atau deskripsi ticket. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter berdasarkan status ticket. */
'status' => ['nullable', Rule::in([
'draft', 'open', 'approved', 'assigned', 'progress', 'pending',
'resolved', 'closed', 'cancelled', 'rejected',
])],
/** Filter berdasarkan prioritas ticket. */
'priority' => ['nullable', Rule::in(['low', 'medium', 'high', 'critical'])],
/** Filter berdasarkan ID tipe ticket. */
'ticket_type_id' => ['nullable', 'integer', 'exists:ticket_types,id'],
/** Filter berdasarkan ID customer. */
'customer_id' => ['nullable', 'integer'],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Requests\TicketIncidentType;
use Illuminate\Foundation\Http\FormRequest;
class IndexTicketIncidentTypeRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari nama incident type. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter status aktif incident type. */
'is_active' => ['nullable', 'boolean'],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\TicketType;
use Illuminate\Foundation\Http\FormRequest;
class IndexTicketTypeRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari kode atau nama tipe ticket. */
'search' => ['nullable', 'string', 'max:255'],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\User;
use App\Enums\UserAccessLevel;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexUserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Kata kunci untuk mencari nama, username, email, atau nomor WhatsApp. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter status akun user. */
'status' => ['nullable', Rule::in(['active', 'inactive', 'suspended'])],
/** Filter level akses user. */
'access_level' => ['nullable', Rule::enum(UserAccessLevel::class)],
/** Nomor halaman yang ingin diambil. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
/** Kolom pengurutan data. */
'sort_by' => ['nullable', Rule::in(['id', 'name', 'username', 'email', 'whatsapp_number', 'access_level', 'status', 'created_at'])],
/** Arah pengurutan data. */
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Http\Requests\User;
use App\Enums\UserAccessLevel;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreUserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'username' => ['nullable', 'string', 'max:255', 'unique:users,username'],
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
'whatsapp_number' => ['nullable', 'string', 'max:20'],
'password' => ['required', 'string', 'min:8'],
'is_master' => ['nullable', 'boolean'],
'access_level' => ['nullable', Rule::enum(UserAccessLevel::class)],
'status' => ['required', Rule::in(['active', 'inactive', 'suspended'])],
'user_profile' => ['nullable', 'array'],
'user_profile.nik' => ['nullable', 'string', 'max:30'],
'user_profile.address' => ['nullable', 'string'],
'user_profile.provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
'user_profile.kabupaten_id' => [
'nullable',
'integer',
Rule::exists('wilayah_kabupaten', 'id')->where(
'provinsi_id',
$this->input('user_profile.provinsi_id')
),
],
'user_profile.kecamatan_id' => [
'nullable',
'integer',
Rule::exists('wilayah_kecamatan', 'id')->where(
'kabupaten_id',
$this->input('user_profile.kabupaten_id')
),
],
'user_profile.desa_id' => [
'nullable',
'integer',
Rule::exists('wilayah_desa', 'id')->where(
'kecamatan_id',
$this->input('user_profile.kecamatan_id')
),
],
'user_tenants' => ['nullable', 'array'],
'user_tenants.*.tenant_id' => ['required_with:user_tenants', 'integer', 'exists:tenants,id'],
'user_tenants.*.is_default' => ['nullable', 'boolean'],
'user_menu_groups' => ['nullable', 'array'],
'user_menu_groups.*.menu_group_id' => ['required_with:user_menu_groups', 'integer', 'exists:menu_groups,id'],
'user_menu_groups.*.tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
];
}
}
@@ -0,0 +1,79 @@
<?php
namespace App\Http\Requests\User;
use App\Enums\UserAccessLevel;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateUserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
$userId = $this->route('user')?->id ?? $this->route('user');
return [
'name' => ['sometimes', 'required', 'string', 'max:255'],
'username' => [
'nullable',
'string',
'max:255',
Rule::unique('users', 'username')->ignore($userId),
],
'email' => [
'sometimes',
'required',
'email',
'max:255',
Rule::unique('users', 'email')->ignore($userId),
],
'whatsapp_number' => ['nullable', 'string', 'max:20'],
'password' => ['nullable', 'string', 'min:8'],
'is_master' => ['nullable', 'boolean'],
'access_level' => ['sometimes', 'required', Rule::enum(UserAccessLevel::class)],
'status' => ['sometimes', 'required', Rule::in(['active', 'inactive', 'suspended'])],
'user_profile' => ['nullable', 'array'],
'user_profile.nik' => ['nullable', 'string', 'max:30'],
'user_profile.address' => ['nullable', 'string'],
'user_profile.provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
'user_profile.kabupaten_id' => [
'nullable',
'integer',
Rule::exists('wilayah_kabupaten', 'id')->where(
'provinsi_id',
$this->input('user_profile.provinsi_id')
),
],
'user_profile.kecamatan_id' => [
'nullable',
'integer',
Rule::exists('wilayah_kecamatan', 'id')->where(
'kabupaten_id',
$this->input('user_profile.kabupaten_id')
),
],
'user_profile.desa_id' => [
'nullable',
'integer',
Rule::exists('wilayah_desa', 'id')->where(
'kecamatan_id',
$this->input('user_profile.kecamatan_id')
),
],
'user_tenants' => ['nullable', 'array'],
'user_tenants.*.tenant_id' => ['required_with:user_tenants', 'integer', 'exists:tenants,id'],
'user_tenants.*.is_default' => ['nullable', 'boolean'],
'user_menu_groups' => ['nullable', 'array'],
'user_menu_groups.*.menu_group_id' => ['required_with:user_menu_groups', 'integer', 'exists:menu_groups,id'],
'user_menu_groups.*.tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
];
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Http\Requests\Wilayah;
use Illuminate\Foundation\Http\FormRequest;
class AlamatLengkapRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'desa_id' => ['nullable', 'required_without_all:kecamatan_id,kabupaten_id,provinsi_id', 'integer', 'exists:wilayah_desa,id'],
'kecamatan_id' => ['nullable', 'required_without_all:desa_id,kabupaten_id,provinsi_id', 'integer', 'exists:wilayah_kecamatan,id'],
'kabupaten_id' => ['nullable', 'required_without_all:desa_id,kecamatan_id,provinsi_id', 'integer', 'exists:wilayah_kabupaten,id'],
'provinsi_id' => ['nullable', 'required_without_all:desa_id,kecamatan_id,kabupaten_id', 'integer', 'exists:wilayah_provinsi,id'],
];
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Http\Requests\Wilayah;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexWilayahRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Pencarian berdasarkan kode atau nama wilayah. */
'search' => ['nullable', 'string', 'max:255'],
/** Filter kabupaten berdasarkan provinsi. */
'provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
/** Filter kecamatan berdasarkan kabupaten. */
'kabupaten_id' => ['nullable', 'integer', 'exists:wilayah_kabupaten,id'],
/** Filter desa berdasarkan kecamatan. */
'kecamatan_id' => ['nullable', 'integer', 'exists:wilayah_kecamatan,id'],
/** Nomor halaman. */
'page' => ['nullable', 'integer', 'min:1'],
/** Jumlah data per halaman, maksimal 100. */
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
/** Kolom pengurutan data. */
'sort_by' => ['nullable', Rule::in(['id', 'kode', 'nama', 'created_at'])],
/** Arah pengurutan data. */
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Requests\Wilayah;
use Illuminate\Foundation\Http\FormRequest;
class LookupWilayahRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
/** Pencarian opsional berdasarkan kode atau nama wilayah. */
'search' => ['nullable', 'string', 'max:100'],
];
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Http\Requests\Wilayah;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreWilayahRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
$tingkat = $this->route('tingkat');
$table = "wilayah_{$tingkat}";
return [
'kode' => ['required', 'string', 'max:20', Rule::unique($table, 'kode')],
'nama' => ['required', 'string', 'max:255'],
'provinsi_id' => [
Rule::requiredIf($tingkat === 'kabupaten'),
'integer',
'exists:wilayah_provinsi,id',
],
'kabupaten_id' => [
Rule::requiredIf($tingkat === 'kecamatan'),
'integer',
'exists:wilayah_kabupaten,id',
],
'kecamatan_id' => [
Rule::requiredIf($tingkat === 'desa'),
'integer',
'exists:wilayah_kecamatan,id',
],
];
}
}
@@ -0,0 +1,52 @@
<?php
namespace App\Http\Requests\Wilayah;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateWilayahRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
$tingkat = $this->route('tingkat');
$table = "wilayah_{$tingkat}";
return [
'kode' => [
'sometimes',
'required',
'string',
'max:20',
Rule::unique($table, 'kode')->ignore($this->route('wilayah')),
],
'nama' => ['sometimes', 'required', 'string', 'max:255'],
'provinsi_id' => [
Rule::excludeIf($tingkat !== 'kabupaten'),
'sometimes',
'required',
'integer',
'exists:wilayah_provinsi,id',
],
'kabupaten_id' => [
Rule::excludeIf($tingkat !== 'kecamatan'),
'sometimes',
'required',
'integer',
'exists:wilayah_kabupaten,id',
],
'kecamatan_id' => [
Rule::excludeIf($tingkat !== 'desa'),
'sometimes',
'required',
'integer',
'exists:wilayah_kecamatan,id',
],
];
}
}