user(); $query = User::query()->where('is_active', true)->whereKeyNot($actor->id) ->whereHas('roles', fn ($roles) => $roles->whereIn('name', ['agent', 'supervisor'])) ->with('roles:id,name', 'teams:id,name'); if (! $actor->hasRole('admin')) { $teamIds = AccessControl::teamIds($actor); $query->whereHas('teams', fn ($teams) => $teams->whereIn('teams.id', $teamIds)); } return response()->json($query->orderBy('name')->get()->map(fn (User $user) => [ 'id' => $user->id, 'name' => $user->name, 'role' => $user->roles->first()?->name, 'team' => $user->teams->first()?->name, ])->values()); } public function assignable(Request $request): JsonResponse { $validated = $request->validate([ 'context' => 'required|in:task', 'entity_type' => 'nullable|required_with:entity_id|in:lead,contact,company,deal,call,campaign', 'entity_id' => 'nullable|required_with:entity_type|integer|min:1', 'search' => 'nullable|string|max:120', ]); $actor = $request->user(); abort_unless($actor->can('create_tasks') || $actor->can('assign_tasks'), 403); if (! empty($validated['entity_type'])) { EntityResolver::authorize($validated['entity_type'], (int) $validated['entity_id']); } $query = User::query()->where('is_active', true)->with(['roles:id,name', 'teams:id,name'])->withCount([ 'assignedTasks as open_tasks_count' => fn ($tasks) => $tasks->active(), ]); if ($actor->hasRole('supervisor')) { $query->whereIn('id', array_values(array_unique(array_merge([$actor->id], AccessControl::teamMemberIds($actor))))); } elseif (! $actor->hasRole('admin')) { $query->whereKey($actor->id); } if (! empty($validated['search'])) { $query->where('name', 'like', '%'.trim($validated['search']).'%'); } $users = $query->orderBy('name')->limit(20)->get()->map(fn (User $user) => [ 'id' => $user->id, 'name' => $user->name, 'avatar' => $user->avatar_url, 'role_label' => $user->roles->first()?->name, 'team_label' => $user->teams->first()?->name, 'is_active' => $user->is_active, 'open_tasks_count' => $user->open_tasks_count, ])->values()->all(); return ApiResponse::success($users); } public function index(Request $request): JsonResponse { Gate::authorize('viewAny', User::class); $query = User::with('roles', 'teams'); if ($request->search) { $query->where(function ($q) use ($request) { $q->where('name', 'like', "%{$request->search}%") ->orWhere('email', 'like', "%{$request->search}%") ->orWhere('phone', 'like', "%{$request->search}%") ->orWhere('voip_extension', 'like', "%{$request->search}%"); }); } if ($request->role) { $query->role($request->role); } if ($request->team_id) { $query->whereHas('teams', fn ($q) => $q->where('teams.id', $request->team_id)); } if ($request->has('is_active')) { $query->where('is_active', filter_var($request->is_active, FILTER_VALIDATE_BOOLEAN)); } $users = $query->orderBy('created_at', 'desc')->paginate($request->per_page ?? 15); return response()->json($users); } public function agents(): JsonResponse { $user = auth()->user(); if ($user?->hasRole('agent')) { return response()->json([$user->load('roles', 'teams')]); } if ($user?->hasRole('supervisor')) { return response()->json( User::role('agent') ->whereIn('id', AccessControl::teamMemberIds($user)) ->where('is_active', true) ->with('roles', 'teams') ->orderBy('name') ->get() ); } return response()->json( User::role('agent') ->where('is_active', true) ->with('roles', 'teams') ->orderBy('name') ->get() ); } public function store(Request $request): JsonResponse { Gate::authorize('create', User::class); $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users', 'password' => ['required', ...PasswordPolicy::rules()], 'phone' => 'nullable|string|max:20', 'voip_extension' => ['nullable', 'string', 'max:20', 'regex:/^[0-9*#]+$/', 'unique:users,voip_extension'], 'role' => 'required|string|exists:roles,name', ]); $user = User::create([ 'name' => $validated['name'], 'email' => $validated['email'], 'password' => Hash::make($validated['password']), 'phone' => $validated['phone'] ?? null, 'voip_extension' => $validated['voip_extension'] ?? null, ]); $user->assignRole($validated['role']); ActivityLogger::log('user_created', "User {$user->email} created"); return response()->json($user->load('roles'), 201); } public function show(User $user): JsonResponse { Gate::authorize('view', $user); return response()->json($user->load('roles.permissions', 'teams')); } public function update(Request $request, User $user): JsonResponse { Gate::authorize('update', $user); $validated = $request->validate([ 'name' => 'sometimes|string|max:255', 'email' => 'sometimes|email|unique:users,email,'.$user->id, 'password' => ['sometimes', ...PasswordPolicy::rules()], 'phone' => 'nullable|string|max:20', 'voip_extension' => ['nullable', 'string', 'max:20', 'regex:/^[0-9*#]+$/', 'unique:users,voip_extension,'.$user->id], 'is_active' => 'sometimes|boolean', ]); if (isset($validated['password'])) { $validated['password'] = Hash::make($validated['password']); } $user->update($validated); if ($request->role) { $user->syncRoles([$request->role]); } ActivityLogger::log('user_updated', "User {$user->email} updated"); return response()->json($user->load('roles', 'teams')); } public function destroy(User $user): JsonResponse { Gate::authorize('delete', $user); $user->delete(); ActivityLogger::log('user_deleted', "User {$user->email} deleted"); return response()->json(['message' => 'کاربر حذف شد']); } public function toggleActive(User $user): JsonResponse { Gate::authorize('update', $user); $user->update(['is_active' => ! $user->is_active]); ActivityLogger::log('user_toggled', "User {$user->email} active: {$user->is_active}"); return response()->json($user); } public function assignRole(Request $request, User $user): JsonResponse { Gate::authorize('update', $user); $request->validate(['role' => 'required|string|exists:roles,name']); $user->syncRoles([$request->role]); return response()->json($user->load('roles')); } public function assignTeam(Request $request, User $user): JsonResponse { Gate::authorize('update', $user); $request->validate(['team_ids' => 'required|array', 'team_ids.*' => 'exists:teams,id']); $user->teams()->sync($request->team_ids); return response()->json($user->load('teams')); } }