Browse Source

Merge branch 'task-container' into dev

moell 10 months ago
parent
commit
21717db23f

+ 85 - 1
app/Http/Controllers/API/TaskController.php

@@ -7,17 +7,21 @@ use App\Http\Requests\API\Task\AssignRequest;
 use App\Http\Requests\API\Task\BatchCreateItemRules;
 use App\Http\Requests\API\Task\BatchCreateRequest;
 use App\Http\Requests\API\Task\CreateOrUpdateRequest;
+use App\Http\Requests\Task\LinkContainerRequest;
 use App\Http\Resources\API\TaskDetailResource;
 use App\Http\Resources\API\TaskResource;
+use App\Models\Container;
 use App\Models\CustomField;
 use App\Models\Enums\ActionObjectType;
 use App\Models\Enums\FileObjectType;
 use App\Models\Enums\ObjectAction;
+use App\Models\Library;
 use App\Models\NamingRule;
 use App\Models\Project;
 use App\Models\Requirement;
 use App\Models\Enums\TaskStatus;
 use App\Models\Task;
+use App\Models\TaskContainer;
 use App\Repositories\ActionRepository;
 use App\Repositories\CustomFieldRepository;
 use App\Services\File\FileAssociationService;
@@ -89,7 +93,9 @@ class TaskController extends Controller
      */
     public function show(string $id)
     {
-        $task = Task::query()->allowed($id)->findOrFail($id);
+        $task = Task::query()->allowed($id)->with([
+            'containers'
+        ])->findOrFail($id);
 
         return new TaskDetailResource($task);
     }
@@ -328,4 +334,82 @@ class TaskController extends Controller
 
         return $this->noContent();
     }
+
+    /**
+     * 容器链接
+     *
+     * @param LinkContainerRequest $request
+     * @param string $id
+     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response
+     */
+    public function linkContainer(LinkContainerRequest $request, string $id)
+    {
+        $task = Task::query()->allowed($id)->findOrFail($id);
+
+        $libraryIds = Library::query()->allowed()->where("project_id", $task->project_id)->pluck("id");
+        if ($libraryIds->isEmpty()) {
+            return $this->badRequest("No container exists for the current task item");
+        }
+
+        $containers = Container::query()
+            ->allowed()
+            ->whereIn("library_id", $libraryIds->toArray())
+            ->whereIn("id", $request->get("container_ids", []))
+            ->get(['id']);
+
+        if (! $containers) {
+            return $this->badRequest("Please select a valid container");
+        }
+
+        foreach ($containers as $container) {
+            TaskContainer::query()->firstOrCreate([
+                'container_id' => $container->id,
+                'task_id' => $task->id
+            ]);
+        }
+
+        return $this->noContent();
+    }
+
+
+    public function unlinkContainer(string $id)
+    {
+        $taskContainer = TaskContainer::query()->findOrFail($id);
+
+        Task::query()->allowed($taskContainer->task_id)->findOrFail($taskContainer->task_id);
+
+        $taskContainer->delete();
+
+        return $this->noContent();
+    }
+
+    /**
+     * 待关联的容器
+     *
+     * @param Request $request
+     * @param string $id
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function containerToBeLinked(Request $request, string $id)
+    {
+        $task = Task::query()->allowed($id)->findOrFail($id);
+
+        $libraryIds = Library::query()->allowed()->where("project_id", $task->project_id)->pluck("id");
+        if ($libraryIds->isEmpty()) {
+            return $this->badRequest("No container exists for the current task item");
+        }
+
+        $containers = Container::query()
+            ->allowed()
+            ->leftJoin("task_container", "containers.id", "=", "task_container.container_id")
+            ->where($request->only(['library_id']))
+            ->whereIn("library_id", $libraryIds->toArray())
+            ->whereNull("task_container.id")
+            ->selectRaw("containers.id, containers.name")
+            ->get();
+
+        return $this->success([
+            'data' => $containers
+        ]);
+    }
 }

+ 28 - 0
app/Http/Requests/Task/LinkContainerRequest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests\Task;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class LinkContainerRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     */
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
+     */
+    public function rules(): array
+    {
+        return [
+            "container_ids" => 'required|array'
+        ];
+    }
+}

+ 23 - 0
app/Http/Resources/API/ContainerSimpleResource.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ContainerSimpleResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'name' => $this->name,
+            'task_container_id' => $this->pivot->id,
+        ];
+    }
+}

+ 2 - 1
app/Http/Resources/API/TaskDetailResource.php

@@ -51,7 +51,8 @@ class TaskDetailResource extends JsonResource
             "created_by" => new UserProfileResource($this->createdBy),
             "custom_fields" => $this->custom_fields,
             "created_at" => (string)$this->created_at,
-            "updated_at" => (string)$this->updated_at
+            "updated_at" => (string)$this->updated_at,
+            "containers" => ContainerSimpleResource::collection($this->containers),
         ];
     }
 }

+ 5 - 0
app/Models/Task.php

@@ -107,4 +107,9 @@ class Task extends Model
         return $this->belongsTo(User::class, 'assign');
     }
 
+    public function containers(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
+    {
+        return $this->belongsToMany(Container::class, "task_container")->withPivot(['id']);
+    }
+
 }

+ 17 - 0
app/Models/TaskContainer.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class TaskContainer extends Model
+{
+    use HasFactory;
+
+    protected $table = "task_container";
+
+    public $timestamps = false;
+
+    protected $fillable = ['task_id', 'container_id'];
+}

+ 28 - 0
database/migrations/2024_05_07_204826_create_task_container_table.php

@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('task_container', function (Blueprint $table) {
+            $table->id();
+            $table->integer("task_id")->index();
+            $table->integer("container_id")->index();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('task_container');
+    }
+};

+ 3 - 0
routes/api.php

@@ -111,6 +111,9 @@ Route::middleware(['auth:sanctum'])->group(function () {
         Route::patch("task/{task}/wait", [API\TaskController::class, "wait"])->name("task.wait");
         Route::post("task-batch-create", [API\TaskController::class, "batchStore"])->name("task.batch-store");
         Route::patch("task/{task}/assign", [API\TaskController::class, "assign"])->name("task.assign");
+        Route::post("task/{task}/container", [API\TaskController::class, "linkContainer"])->name("task.link-container");
+        Route::delete("task-container/{task_container}", [API\TaskController::class, "unlinkContainer"])->name("task.unlink-container");
+        Route::get("task/{task}/container-to-be-linked", [API\TaskController::class, "containerToBeLinked"])->name("task.container-to-be-linked");
 
         Route::post("user/user-batch-create", [API\UserController::class, "batchStore"])->name("user.batch-create");
         Route::put("user/status/{status}", [API\UserController::class, "status"])->name("user.status");