CRM/backend/app/Http/Controllers/Api/TaskController.php

169 خطوط
6.8 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Enums\TaskStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssignTaskRequest;
use App\Http\Requests\StoreTaskRequest;
use App\Http\Requests\TaskIndexRequest;
use App\Http\Requests\UpdateTaskRequest;
use App\Http\Resources\TaskResource;
use App\Http\Responses\ApiResponse;
use App\Models\Task;
use App\Services\TaskService;
use App\Support\AccessControl;
use App\Support\EntityResolver;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class TaskController extends Controller
{
public function __construct(private TaskService $service) {}
public function index(TaskIndexRequest $request): JsonResponse
{
Gate::authorize('viewAny', Task::class);
$validated = $request->validated();
$query = Task::with(['assignee:id,name,avatar', 'assigner:id,name', 'creator:id,name', 'taskable', 'parent:id,subject']);
AccessControl::scopeTasks($query, $request->user());
foreach (['status', 'priority', 'assigned_to', 'created_by'] as $filter) {
if (array_key_exists($filter, $validated)) {
$query->where($filter, $validated[$filter]);
}
}
if (! empty($validated['due_from'])) {
$query->where('due_at', '>=', $validated['due_from']);
}
if (! empty($validated['due_to'])) {
$query->where('due_at', '<=', $validated['due_to']);
}
if ($request->boolean('overdue')) {
$query->active()->whereNotNull('due_at')->where('due_at', '<', now());
}
if (! empty($validated['taskable_type'])) {
$query->where('taskable_type', EntityResolver::classFor($validated['taskable_type']));
}
if (! empty($validated['taskable_id'])) {
$query->where('taskable_id', $validated['taskable_id']);
}
if (! empty($validated['search'])) {
$search = trim($validated['search']);
$query->where(fn ($searchQuery) => $searchQuery
->where('subject', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%"));
}
[$sortColumn, $sortDirection] = $this->sort($validated['sort'] ?? '-created_at');
$paginator = $query->orderBy($sortColumn, $sortDirection)->paginate((int) ($validated['per_page'] ?? 20));
return ApiResponse::paginated($paginator, fn (Task $task) => $this->resource($task));
}
public function store(StoreTaskRequest $request): JsonResponse
{
Gate::authorize('create', Task::class);
$task = $this->service->create($request->validated(), $request->user());
return ApiResponse::success($this->resource($task), 201, 'کار ایجاد شد.');
}
public function show(Task $task): JsonResponse
{
Gate::authorize('view', $task);
return ApiResponse::success($this->resource($task->load(['assignee:id,name,avatar', 'assigner:id,name', 'creator:id,name', 'taskable', 'parent:id,subject'])));
}
public function update(UpdateTaskRequest $request, Task $task): JsonResponse
{
Gate::authorize('update', $task);
$updated = $this->service->update($task, $request->validated(), $request->user());
return ApiResponse::success($this->resource($updated), message: 'کار ویرایش شد.');
}
public function destroy(Task $task): JsonResponse
{
Gate::authorize('delete', $task);
$this->service->delete($task);
return ApiResponse::success(null, message: 'کار حذف شد.');
}
public function assign(AssignTaskRequest $request, Task $task): JsonResponse
{
Gate::authorize('assign', [$task, (int) $request->validated('assigned_to')]);
$updated = $this->service->assign($task, (int) $request->validated('assigned_to'), (int) $request->validated('version'), $request->user());
return ApiResponse::success($this->resource($updated), message: 'مسئول کار تغییر کرد.');
}
public function start(Request $request, Task $task): JsonResponse
{
$validated = $request->validate(['version' => 'required|integer|min:1']);
$updated = $this->service->transition($task, TaskStatus::InProgress, (int) $validated['version'], $request->user());
return ApiResponse::success($this->resource($updated), message: 'کار شروع شد.');
}
public function complete(Request $request, Task $task): JsonResponse
{
$validated = $request->validate(['version' => 'required|integer|min:1']);
$updated = $this->service->transition($task, TaskStatus::Done, (int) $validated['version'], $request->user());
return ApiResponse::success($this->resource($updated), message: 'کار تکمیل شد.');
}
public function reopen(Request $request, Task $task): JsonResponse
{
$validated = $request->validate(['version' => 'required|integer|min:1']);
$updated = $this->service->transition($task, TaskStatus::Open, (int) $validated['version'], $request->user());
return ApiResponse::success($this->resource($updated), message: 'کار بازگشایی شد.');
}
public function cancel(Request $request, Task $task): JsonResponse
{
$validated = $request->validate(['version' => 'required|integer|min:1']);
$updated = $this->service->transition($task, TaskStatus::Cancelled, (int) $validated['version'], $request->user());
return ApiResponse::success($this->resource($updated), message: 'کار لغو شد.');
}
public function bulkAssign(Request $request): JsonResponse
{
$validated = $request->validate([
'task_ids' => 'required|array|min:1|max:100',
'task_ids.*' => 'required|integer|distinct',
'assigned_to' => 'required|integer|exists:users,id',
]);
$tasks = $this->service->bulkAssign($validated['task_ids'], (int) $validated['assigned_to'], $request->user());
return ApiResponse::success(array_map(fn (Task $task) => $this->resource($task), $tasks), message: 'کارها تخصیص داده شدند.');
}
public function bulkComplete(Request $request): JsonResponse
{
$validated = $request->validate([
'task_ids' => 'required|array|min:1|max:100',
'task_ids.*' => 'required|integer|distinct',
]);
$tasks = $this->service->bulkComplete($validated['task_ids'], $request->user());
return ApiResponse::success(array_map(fn (Task $task) => $this->resource($task), $tasks), message: 'کارها تکمیل شدند.');
}
private function resource(Task $task): array
{
return (new TaskResource($task))->resolve(request());
}
private function sort(string $sort): array
{
return str_starts_with($sort, '-') ? [substr($sort, 1), 'desc'] : [$sort, 'asc'];
}
}