big update base struktur tahap 1
This commit is contained in:
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\User;
|
||||
|
||||
use App\Enums\UserAccessLevel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class UserService
|
||||
{
|
||||
public function list(array $filters = [], ?User $actor = null, ?int $tenantId = null)
|
||||
{
|
||||
return User::query()
|
||||
->with(['profilePhoto', 'userProfile', 'userTenants.tenant', 'userMenuGroups.menuGroup', 'userMenuGroups.tenant'])
|
||||
->when(
|
||||
! empty($filters['search']),
|
||||
fn ($q) => $q->where(function ($x) use ($filters) {
|
||||
$x->where('name', 'ILIKE', "%{$filters['search']}%")
|
||||
->orWhere('username', 'ILIKE', "%{$filters['search']}%")
|
||||
->orWhere('email', 'ILIKE', "%{$filters['search']}%")
|
||||
->orWhere('whatsapp_number', 'ILIKE', "%{$filters['search']}%");
|
||||
})
|
||||
)
|
||||
->when(
|
||||
isset($filters['status']) && $filters['status'] !== '',
|
||||
fn ($q) => $q->where('status', $filters['status'])
|
||||
)
|
||||
->when(
|
||||
! empty($filters['access_level']),
|
||||
fn ($q) => $q->where('access_level', $filters['access_level'])
|
||||
)
|
||||
->when(
|
||||
$actor && ! $actor->isMasterAdmin(),
|
||||
fn ($q) => $q->whereHas(
|
||||
'userTenants',
|
||||
fn ($tenantQuery) => $tenantQuery->where('tenant_id', $tenantId)
|
||||
)->where('is_master', false)
|
||||
)
|
||||
->orderBy(
|
||||
$filters['sort_by'] ?? 'id',
|
||||
$filters['sort_direction'] ?? 'desc'
|
||||
)
|
||||
->paginate($filters['per_page'] ?? 10);
|
||||
}
|
||||
|
||||
public function create(array $payload, ?User $actor = null): User
|
||||
{
|
||||
$this->guardPrivilegeChange($payload, $actor);
|
||||
$this->guardTenantPayload($payload, $actor);
|
||||
|
||||
if ($actor && ! $actor->isMasterAdmin() && empty($payload['user_tenants'])) {
|
||||
throw ValidationException::withMessages([
|
||||
'user_tenants' => 'Tenant Owner wajib membuat user pada tenant aktif.',
|
||||
]);
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($payload) {
|
||||
$baseData = Arr::only($payload, [
|
||||
'name',
|
||||
'username',
|
||||
'email',
|
||||
'whatsapp_number',
|
||||
'profile_photo_file_id',
|
||||
'password',
|
||||
'is_master',
|
||||
'access_level',
|
||||
'status',
|
||||
]);
|
||||
|
||||
$user = User::create($baseData);
|
||||
|
||||
$this->syncProfile($user, $payload['user_profile'] ?? null);
|
||||
$this->syncTenants($user, $payload['user_tenants'] ?? []);
|
||||
$this->syncMenuGroups($user, $payload['user_menu_groups'] ?? []);
|
||||
|
||||
return $user->fresh([
|
||||
'userProfile',
|
||||
'profilePhoto',
|
||||
'userTenants.tenant',
|
||||
'userMenuGroups.menuGroup',
|
||||
'userMenuGroups.tenant',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function show(User $user): User
|
||||
{
|
||||
return $user->load([
|
||||
'userProfile',
|
||||
'profilePhoto',
|
||||
'userTenants.tenant',
|
||||
'userMenuGroups.menuGroup',
|
||||
'userMenuGroups.tenant',
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(User $user, array $payload, ?User $actor = null): User
|
||||
{
|
||||
$this->guardPrivilegeChange($payload, $actor, $user);
|
||||
$this->guardTenantPayload($payload, $actor);
|
||||
|
||||
return DB::transaction(function () use ($user, $payload) {
|
||||
$baseData = Arr::only($payload, [
|
||||
'name',
|
||||
'username',
|
||||
'email',
|
||||
'whatsapp_number',
|
||||
'profile_photo_file_id',
|
||||
'is_master',
|
||||
'access_level',
|
||||
'status',
|
||||
]);
|
||||
|
||||
if (! empty($payload['password'])) {
|
||||
$baseData['password'] = $payload['password'];
|
||||
}
|
||||
|
||||
if (! empty($baseData)) {
|
||||
$user->update($baseData);
|
||||
}
|
||||
|
||||
if (array_key_exists('user_profile', $payload)) {
|
||||
$this->syncProfile($user, $payload['user_profile']);
|
||||
}
|
||||
|
||||
if (array_key_exists('user_tenants', $payload)) {
|
||||
$this->syncTenants($user, $payload['user_tenants'] ?? []);
|
||||
}
|
||||
|
||||
if (array_key_exists('user_menu_groups', $payload)) {
|
||||
$this->syncMenuGroups($user, $payload['user_menu_groups'] ?? []);
|
||||
}
|
||||
|
||||
return $user->fresh([
|
||||
'userProfile',
|
||||
'profilePhoto',
|
||||
'userTenants.tenant',
|
||||
'userMenuGroups.menuGroup',
|
||||
'userMenuGroups.tenant',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function delete(User $user): void
|
||||
{
|
||||
DB::transaction(function () use ($user) {
|
||||
$user->userProfile()->delete();
|
||||
$user->userTenants()->delete();
|
||||
$user->userMenuGroups()->delete();
|
||||
$user->delete();
|
||||
});
|
||||
}
|
||||
|
||||
protected function syncProfile(User $user, ?array $profile): void
|
||||
{
|
||||
if ($profile === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = Arr::only($profile, [
|
||||
'nik',
|
||||
'address',
|
||||
'provinsi_id',
|
||||
'kabupaten_id',
|
||||
'kecamatan_id',
|
||||
'desa_id',
|
||||
]);
|
||||
|
||||
$user->userProfile()->updateOrCreate(
|
||||
['user_id' => $user->id],
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
protected function syncTenants(User $user, array $rows): void
|
||||
{
|
||||
$normalized = collect($rows)
|
||||
->map(fn ($row) => [
|
||||
'tenant_id' => $row['tenant_id'] ?? null,
|
||||
'is_default' => (bool) ($row['is_default'] ?? false),
|
||||
])
|
||||
->filter(fn ($row) => ! empty($row['tenant_id']))
|
||||
->unique('tenant_id')
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$defaultSet = false;
|
||||
foreach ($normalized as $index => $row) {
|
||||
if ($row['is_default'] && ! $defaultSet) {
|
||||
$defaultSet = true;
|
||||
} else {
|
||||
$normalized[$index]['is_default'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $defaultSet && count($normalized) > 0) {
|
||||
$normalized[0]['is_default'] = true;
|
||||
}
|
||||
|
||||
$user->userTenants()->delete();
|
||||
|
||||
if (! empty($normalized)) {
|
||||
$user->userTenants()->createMany($normalized);
|
||||
}
|
||||
}
|
||||
|
||||
protected function syncMenuGroups(User $user, array $rows): void
|
||||
{
|
||||
$normalized = collect($rows)
|
||||
->map(fn ($row) => [
|
||||
'menu_group_id' => $row['menu_group_id'] ?? null,
|
||||
'tenant_id' => $row['tenant_id'] ?? null,
|
||||
])
|
||||
->filter(fn ($row) => ! empty($row['menu_group_id']))
|
||||
->unique(fn ($row) => ($row['menu_group_id'] ?? '').'|'.($row['tenant_id'] ?? ''))
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$user->userMenuGroups()->delete();
|
||||
|
||||
if (! empty($normalized)) {
|
||||
$user->userMenuGroups()->createMany($normalized);
|
||||
}
|
||||
}
|
||||
|
||||
protected function guardPrivilegeChange(array &$payload, ?User $actor, ?User $target = null): void
|
||||
{
|
||||
if (! $actor) {
|
||||
unset($payload['is_master'], $payload['access_level']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($actor->isMasterAdmin()) {
|
||||
if (($payload['access_level'] ?? null) === UserAccessLevel::MASTER_ADMIN->value) {
|
||||
$payload['is_master'] = true;
|
||||
} elseif (array_key_exists('access_level', $payload)) {
|
||||
$payload['is_master'] = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($target?->isMasterAdmin()) {
|
||||
throw ValidationException::withMessages([
|
||||
'user' => 'Master Admin hanya dapat diubah oleh Master Admin.',
|
||||
]);
|
||||
}
|
||||
|
||||
if (($payload['is_master'] ?? false)
|
||||
|| ($payload['access_level'] ?? null) === UserAccessLevel::MASTER_ADMIN->value
|
||||
|| ($payload['access_level'] ?? null) === UserAccessLevel::TENANT_OWNER->value) {
|
||||
throw ValidationException::withMessages([
|
||||
'access_level' => 'Anda tidak dapat memberikan level akses ini.',
|
||||
]);
|
||||
}
|
||||
|
||||
unset($payload['is_master']);
|
||||
}
|
||||
|
||||
protected function guardTenantPayload(array $payload, ?User $actor): void
|
||||
{
|
||||
if (! $actor || $actor->isMasterAdmin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tenantId = request()->attributes->get('tenant_id');
|
||||
|
||||
foreach (['user_tenants', 'user_menu_groups'] as $key) {
|
||||
foreach ($payload[$key] ?? [] as $row) {
|
||||
if ((int) ($row['tenant_id'] ?? 0) !== (int) $tenantId) {
|
||||
throw ValidationException::withMessages([
|
||||
$key => 'Assignment hanya boleh dibuat untuk tenant yang sedang aktif.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user