Browse Source

Merge branch 'project-management' of kyle/autocde2.0 into dev

Mo 1 year ago
parent
commit
60d2d5beb0

+ 82 - 3
app/Http/Controllers/API/ProjectController.php

@@ -4,7 +4,9 @@ namespace App\Http\Controllers\API;
 
 use App\Http\Controllers\Controller;
 use App\Http\Requests\API\Project\CreateOrUpdateRequest;
+use App\Http\Requests\API\Project\PostponeRequest;
 use App\Http\Resources\API\ProjectResource;
+use App\Models\Enums\ProjectStatus;
 use App\Models\Project;
 use App\Models\ProjectAsset;
 use App\Models\ProjectPlan;
@@ -76,9 +78,40 @@ class ProjectController extends Controller
     /**
      * Update the specified resource in storage.
      */
-    public function update(Request $request, string $id)
+    public function update(CreateOrUpdateRequest $request, string $id)
     {
-        //
+        $project = Project::findOrFail($id);
+
+        $project->fill([
+            ...$request->all(),
+            'whitelist' => $request->whitelist ? sprintf(",%s", implode(',', $request->whitelist)) : null,
+        ]);
+
+        $project->save();
+
+        if ($request->has("assets")) {
+            ProjectAsset::where('project_id', $project->id)->delete();
+
+            foreach ($request->get("assets", []) as $assetId) {
+                ProjectAsset::create([
+                    'project_id' => $project->id,
+                    'asset_id' => $assetId,
+                ]);
+            }
+        }
+
+        if ($request->has("plans")) {
+            ProjectPlan::where('project_id', $project->id)->delete();
+
+            foreach ($request->get("plans", []) as $planId) {
+                ProjectPlan::create([
+                    'project_id' => $project->id,
+                    'plan_id' => $planId,
+                ]);
+            }
+        }
+
+        return $this->noContent();
     }
 
     /**
@@ -86,6 +119,52 @@ class ProjectController extends Controller
      */
     public function destroy(string $id)
     {
-        //
+        $project = Project::findOrFail($id);
+
+        $project->delete();
+
+        return $this->noContent();
+    }
+
+    public function closed(string $id)
+    {
+        $project = Project::findOrFail($id);
+
+        $project->status = ProjectStatus::CLOSED->value;
+        $project->save();
+
+        return $this->noContent();
+    }
+
+    public function start(string $id)
+    {
+        $project = Project::findOrFail($id);
+
+        $project->status = ProjectStatus::DOING->value;
+        $project->save();
+
+        return $this->noContent();
+    }
+
+    public function pause(string $id)
+    {
+        $project = Project::findOrFail($id);
+
+        $project->status = ProjectStatus::PAUSE->value;
+        $project->save();
+
+        return $this->noContent();
+    }
+
+    public function postpone(PostponeRequest $request, string $id)
+    {
+        $project = Project::findOrFail($id);
+
+        $project->fill($request->only([
+            'begin', 'end', 'available_days'
+        ]));
+        $project->save();
+
+        return $this->noContent();
     }
 }

+ 3 - 2
app/Http/Requests/API/Project/CreateOrUpdateRequest.php

@@ -35,10 +35,11 @@ class CreateOrUpdateRequest extends FormRequest
                 'max:50',
             ],
             'const' => 'numeric',
-            'begin' => 'date',
-            'end' => 'date',
+            'begin' => 'required|date',
+            'end' => 'required|date',
             'type' => 'required|max:20',
             'acl' => 'required|in:private,custom',
+            'available_days' => 'numeric',
             'whitelist' => [
                 'array',
                 function ($attribute, $value, $fail) {

+ 30 - 0
app/Http/Requests/API/Project/PostponeRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests\API\Project;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class PostponeRequest 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 [
+            'begin' => 'required|date',
+            'end' => 'required|date',
+            'available_days' => 'numeric',
+        ];
+    }
+}

+ 21 - 0
app/Models/Enums/ProjectStatus.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Models\Enums;
+
+enum ProjectStatus: string
+{
+    case WAIT = 'wait'; //未开始
+
+    case DOING = 'doing'; //进行中
+
+    case DONE = 'done'; //完成
+
+    case PAUSE = 'pause'; //暂停
+
+    case CANCEL = 'cancel'; //取消
+
+    case CLOSED = 'closed'; //关闭
+
+    case PENDING_REVIEW = 'pending_review'; //待审核
+
+}

+ 5 - 0
routes/api.php

@@ -32,4 +32,9 @@ Route::middleware(['auth:sanctum'])->group(function () {
         'requirement' => API\RequirementController::class,
         'project' => API\ProjectController::class,
     ]);
+
+    Route::patch("project/{project}/closed", [API\ProjectController::class, "closed"])->name("project.closed");
+    Route::patch("project/{project}/start", [API\ProjectController::class, "start"])->name("project.start");
+    Route::patch("project/{project}/pause", [API\ProjectController::class, "pause"])->name("project.pause");
+    Route::patch("project/{project}/postpone", [API\ProjectController::class, "postpone"])->name("project.postpone");
 });

+ 85 - 0
tests/Feature/API/ProjectTest.php

@@ -3,8 +3,10 @@
 namespace Tests\Feature\API;
 
 use App\Models\Asset;
+use App\Models\Enums\ProjectStatus;
 use App\Models\Plan;
 use App\Models\Project;
+use Carbon\Carbon;
 use Illuminate\Foundation\Testing\RefreshDatabase;
 use Illuminate\Foundation\Testing\WithFaker;
 use Tests\Feature\TestCase;
@@ -56,4 +58,87 @@ class ProjectTest extends TestCase
 
         $response->assertStatus(201);
     }
+
+    public function test_project_update(): void
+    {
+        $project = Project::factory()->create();
+
+        $form = Project::factory()->make();
+        $form->whitelist = [1];
+
+        $form->plans = [
+            Plan::factory()->create()->id,
+            Plan::factory()->create()->id,
+        ];
+
+        $form->assets = [
+            Asset::factory()->create()->id,
+            Asset::factory()->create()->id,
+        ];
+
+        $response = $this->put(route('project.update', ['project' => $project->id]), $form->toArray());
+
+        $response->assertStatus(204);
+
+        $newAsset = Project::find($project->id);
+
+        $this->assertEquals($form->name, $newAsset->name);
+    }
+
+    public function test_project_delete(): void
+    {
+        $project = Project::factory()->create();
+
+        $response = $this->delete(route('project.destroy', ['project' => $project->id]));
+
+        $response->assertStatus(204);
+
+        $this->assertNull(Project::find($project->id));
+    }
+
+    public function test_project_closed(): void
+    {
+        $project = Project::factory()->create();
+
+        $response = $this->patch(route('project.closed', ['project' => $project->id]));
+
+        $response->assertStatus(204);
+
+        $this->assertEquals(Project::find($project->id)->status, ProjectStatus::CLOSED->value);
+    }
+
+    public function test_project_start(): void
+    {
+        $project = Project::factory()->create();
+
+        $response = $this->patch(route('project.start', ['project' => $project->id]));
+
+        $response->assertStatus(204);
+
+        $this->assertEquals(Project::find($project->id)->status, ProjectStatus::DOING->value);
+    }
+
+    public function test_project_pause(): void
+    {
+        $project = Project::factory()->create();
+
+        $response = $this->patch(route('project.pause', ['project' => $project->id]));
+
+        $response->assertStatus(204);
+
+        $this->assertEquals(Project::find($project->id)->status, ProjectStatus::PAUSE->value);
+    }
+
+    public function test_project_postpone(): void
+    {
+        $project = Project::factory()->create();
+
+        $response = $this->patch(route('project.postpone', ['project' => $project->id]), [
+            'begin' => Carbon::now()->toDateString(),
+            'end' => Carbon::now()->addDays(3)->toDateString(),
+            'available_days' => 3,
+        ]);
+
+        $response->assertStatus(204);
+    }
 }