Browse Source

task migration & task create

moell 1 year ago
parent
commit
0aac4cb2be

+ 59 - 0
app/Http/Controllers/API/TaskController.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Http\Controllers\API;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\API\Task\CreateOrUpdateRequest;
+use App\Models\Task;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class TaskController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     */
+    public function index()
+    {
+        //
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     */
+    public function store(CreateOrUpdateRequest $request)
+    {
+        Task::create([
+            ...$request->all(),
+            'company_id' => Auth::user()->company_id,
+            'created_by' => Auth::id(),
+            'whitelist' => $request->whitelist ? sprintf(",%s", implode(',', $request->whitelist)) : null,
+        ]);
+
+        return $this->created();
+    }
+
+    /**
+     * Display the specified resource.
+     */
+    public function show(string $id)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     */
+    public function update(Request $request, string $id)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     */
+    public function destroy(string $id)
+    {
+        //
+    }
+}

+ 66 - 0
app/Http/Requests/API/Task/CreateOrUpdateRequest.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Http\Requests\API\Task;
+
+use App\Http\Requests\RuleHelper;
+use App\Models\Enums\TaskACL;
+use App\Models\User;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Validation\Rule;
+use Illuminate\Validation\Rules\Enum;
+
+class CreateOrUpdateRequest extends FormRequest
+{
+    use RuleHelper;
+
+    /**
+     * 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 [
+            'project_id' => [
+                'required',
+                Rule::exists('projects', 'id')->where($this->userCompanyWhere()),
+            ],
+            'requirement_id' => [
+                'required',
+                Rule::exists('requirements', 'id')->where($this->userCompanyWhere()),
+            ],
+            'naming_rule_id' => [
+                Rule::when($this->get('naming_rule_id') > 0, [
+                    Rule::exists('naming_rules', 'id')->whereIn('company_id', [
+                        0, Auth::user()->company_id,
+                    ]),
+                ])
+            ],
+            'assign' => [
+                Rule::exists('users', 'id')->where($this->userCompanyWhere()),
+            ],
+            'name' => 'required|max:255',
+            'parent_id' => [
+                Rule::when($this->get('parent_id') > 0, [
+                    Rule::exists('tasks', 'id')->where($this->userCompanyWhere())->where("parent_id", 0),
+                ])
+            ],
+            'begin' => 'date',
+            'end' => 'date',
+            'acl' => [
+                new Enum(TaskACL::class),
+            ],
+            'whitelist' => $this->usersCompanyRules(),
+            'mailto' => $this->usersCompanyRules(),
+        ];
+    }
+}

+ 14 - 0
app/Http/Requests/RuleHelper.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Requests;
 
+use App\Models\User;
 use Illuminate\Database\Query\Builder;
 use Illuminate\Support\Facades\Auth;
 
@@ -11,4 +12,17 @@ trait RuleHelper
     {
         return fn (Builder $query) => $query->where('company_id', Auth::user()->company_id);
     }
+
+    protected function usersCompanyRules(): array
+    {
+        return [
+            'array',
+            function ($attribute, $value, $fail) {
+                $userCount = User::where("company_id", Auth::user()->company_id)->whereIn('id', $value)->count();
+                if ($userCount != count($value)) {
+                    $fail('The selected user is invalid.');
+                }
+            }
+        ];
+    }
 }

+ 19 - 0
app/Http/Resources/API/TaskDetailResource.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class TaskDetailResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return parent::toArray($request);
+    }
+}

+ 16 - 0
app/ModelFilters/TaskFilter.php

@@ -0,0 +1,16 @@
+<?php 
+
+namespace App\ModelFilters;
+
+use EloquentFilter\ModelFilter;
+
+class TaskFilter extends ModelFilter
+{
+    /**
+    * Related Models that have ModelFilters as well as the method on the ModelFilter
+    * As [relationMethod => [input_key1, input_key2]].
+    *
+    * @var array
+    */
+    public $relations = [];
+}

+ 10 - 0
app/Models/Enums/TaskACL.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Models\Enums;
+
+enum TaskACL: string
+{
+    case PRIVATE = 'private';
+
+    case CUSTOM = 'custom';
+}

+ 18 - 0
app/Models/Enums/TaskStatus.php

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

+ 21 - 0
app/Models/Task.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Models;
+
+use EloquentFilter\Filterable;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Task extends Model
+{
+    use HasFactory, Filterable;
+
+    protected $guarded = [
+        'id'
+    ];
+
+    protected $casts = [
+        'mailto' => 'array',
+        'custom_fields' => 'array',
+    ];
+}

+ 45 - 0
database/factories/TaskFactory.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Enums\TaskACL;
+use App\Models\Enums\TaskStatus;
+use App\Models\Project;
+use App\Models\Requirement;
+use App\Models\User;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Task>
+ */
+class TaskFactory extends Factory
+{
+    /**
+     * Define the model's default state.
+     *
+     * @return array<string, mixed>
+     */
+    public function definition(): array
+    {
+        return [
+            'project_id' => Project::factory()->create(),
+            'requirement_id' => Requirement::factory()->create(),
+            'naming_rule_id' => 0,
+            'name' => fake()->title(),
+            'status' => TaskStatus::WAIT->value,
+            'parent_id' => 0,
+            'description' => fake()->text(),
+            'begin' => Carbon::now()->toDateString(),
+            'end' => Carbon::now()->addMonth()->toDateString(),
+            'email_subject' => fake()->title(),
+            'acl' => TaskACL::PRIVATE->value,
+            'whitelist' => ',1,',
+            'created_by' => Auth::id(),
+            'mailto' => [
+                Auth::id(),
+            ],
+        ];
+    }
+}

+ 57 - 0
database/migrations/2024_02_23_122917_create_tasks_table.php

@@ -0,0 +1,57 @@
+<?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('tasks', function (Blueprint $table) {
+            $table->id();
+            $table->string("name", 150);
+            $table->integer("project_id");
+            $table->integer("requirement_id")->nullable();
+            $table->integer("naming_rule_id")->nullable();
+            $table->integer("parent_id");
+            $table->string("task_type", 50)->nullable();
+            $table->string("doc_stage", 50)->nullable();
+            $table->string("doc_type", 50)->nullable();
+            $table->string("status")->default('wait')->comment('wait,doing,done,pause,cancel,closed');
+            $table->integer("assign")->nullable();
+            $table->text("description")->nullable();
+            $table->date("begin")->nullable();
+            $table->date("end")->nullable();
+            $table->json('mailto')->nullable();
+            $table->string('email_subject')->nullable();
+            $table->string('acl')->default('private')->comment('private,custom');
+            $table->string("whitelist")->nullable();
+            $table->integer('closed_by')->nullable();
+            $table->dateTime("closed_at")->nullable();
+            $table->integer('canceled_by')->nullable();
+            $table->dateTime("canceled_at")->nullable();
+            $table->integer('approve_by')->nullable();
+            $table->dateTime("approve_at")->nullable();
+            $table->integer('finished_by')->nullable();
+            $table->dateTime("finished_at")->nullable();
+            $table->integer('review_by')->nullable();
+            $table->dateTime("review_at")->nullable();
+            $table->integer('created_by')->nullable();
+            $table->json("custom_fields")->nullable();
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('tasks');
+    }
+};

+ 1 - 0
routes/api.php

@@ -33,6 +33,7 @@ Route::middleware(['auth:sanctum'])->group(function () {
             'role' => API\RoleController::class,
             'custom-field' => API\CustomFieldController::class,
             'naming-rule' => API\NameRuleController::class,
+            'task' => API\TaskController::class,
         ]);
 
         Route::get("requirement/{asset_id}/asset", [API\RequirementController::class, "byAsset"])->name("requirement.byAsset");

+ 25 - 0
tests/Feature/API/TaskTest.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace Tests\Feature\API;
+
+use App\Models\Task;
+use App\Models\User;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Illuminate\Support\Facades\Auth;
+use Tests\Feature\TestCase;
+
+class TaskTest extends TestCase
+{
+    public function test_create_task(): void
+    {
+        $form = Task::factory()->make();
+        $form->whitelist = [
+            Auth::id(),
+        ];
+
+        $response = $this->postJson(route('task.store'), $form->toArray());
+
+        $response->assertStatus(201);
+    }
+}

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

@@ -1,20 +0,0 @@
-<?php
-
-namespace Tests\Feature\tests\Feature\API;
-
-use Illuminate\Foundation\Testing\RefreshDatabase;
-use Illuminate\Foundation\Testing\WithFaker;
-use Tests\TestCase;
-
-class ProjectTest.php extends TestCase
-{
-    /**
-     * A basic feature test example.
-     */
-    public function test_example(): void
-    {
-        $response = $this->get('/');
-
-        $response->assertStatus(200);
-    }
-}