169 خطوط
6.8 KiB
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'];
|
|
}
|
|
}
|