245 خطوط
8.3 KiB
PHP
245 خطوط
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Responses\ApiResponse;
|
|
use App\Models\User;
|
|
use App\Services\ActivityLogger;
|
|
use App\Support\AccessControl;
|
|
use App\Support\EntityResolver;
|
|
use App\Support\PasswordPolicy;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\Hash;
|
|
|
|
class UserController extends Controller
|
|
{
|
|
public function referralTargets(Request $request): JsonResponse
|
|
{
|
|
$actor = $request->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'));
|
|
}
|
|
}
|