Browse Source

Merge branch 'project-team' into dev

moell 1 year ago
parent
commit
2533b6c160

+ 39 - 0
app/Http/Controllers/API/TeamMemberController.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Http\Controllers\API;
+
+use App\Http\Controllers\Controller;
+use App\Http\Resources\API\TeamMemberResource;
+use App\Models\Project;
+use App\Models\TeamMember;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class TeamMemberController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     */
+    public function members(string $projectId)
+    {
+        $project = Project::query()->findOrFail($projectId);
+
+        return TeamMemberResource::collection($project->teamMembers);
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     */
+    public function destroy(string $id)
+    {
+        $teamMember = TeamMember::query()->findOrFail($id);
+
+        if ($teamMember->project?->company_id != Auth::user()->company_id) {
+            return $this->forbidden('No permission to delete');
+        }
+
+        $teamMember->delete();
+
+        return $this->noContent();
+    }
+}

+ 26 - 0
app/Http/Resources/API/TeamMemberResource.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class TeamMemberResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'user' => new UserProfileResource($this->user),
+            'user_id' => $this->user_id,
+            'role' => $this->role,
+            'limited' => $this->limited,
+            'join_at' => (string)$this->join_at,
+        ];
+    }
+}

+ 5 - 0
app/Models/Project.php

@@ -34,4 +34,9 @@ class Project extends Model
     {
         return $this->belongsToMany(Requirement::class, 'project_requirement');
     }
+
+    public function teamMembers(): \Illuminate\Database\Eloquent\Relations\HasMany
+    {
+        return $this->hasMany(TeamMember::class);
+    }
 }

+ 21 - 0
app/Models/TeamMember.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class TeamMember extends Model
+{
+    use HasFactory;
+
+    public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
+    {
+        return $this->belongsTo(User::class);
+    }
+
+    public function project(): \Illuminate\Database\Eloquent\Relations\BelongsTo
+    {
+        return $this->belongsTo(Project::class);
+    }
+}

+ 32 - 0
database/factories/TeamMemberFactory.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Project;
+use App\Models\User;
+use Carbon\Carbon;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\TeamMember>
+ */
+class TeamMemberFactory extends Factory
+{
+    /**
+     * Define the model's default state.
+     *
+     * @return array<string, mixed>
+     */
+    public function definition(): array
+    {
+        return [
+            'join_at' => Carbon::now(),
+            'project_id' => Project::factory(),
+            'user_id' => User::factory(),
+            'created_by' => Auth::id(),
+            'role' => fake()->text(10),
+            'limited' => false,
+        ];
+    }
+}

+ 33 - 0
database/migrations/2024_02_26_120957_create_team_members_table.php

@@ -0,0 +1,33 @@
+<?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('team_members', function (Blueprint $table) {
+            $table->id();
+            $table->integer("project_id")->index();
+            $table->integer("user_id");
+            $table->date("join_at");
+            $table->string("role", 40)->nullable();
+            $table->boolean("limited")->default(false);
+            $table->integer("created_by")->nullable();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('team_members');
+    }
+};

+ 3 - 0
routes/api.php

@@ -67,5 +67,8 @@ Route::middleware(['auth:sanctum'])->group(function () {
         Route::get("custom-field-group", [API\CustomFieldController::class, "groups"])->name("custom-field.groups");
 
         Route::get("naming-rule-enabled", [API\NameRuleController::class, "enabled"])->name("naming-rule.enabled");
+
+        Route::get("team-member/{project}", [API\TeamMemberController::class, "members"])->name("team-member.list");
+        Route::delete("team-member/{team_member}", [API\TeamMemberController::class, "destroy"])->name("team-member.destroy");
     });
 });

+ 44 - 0
tests/Feature/API/TeamMemberTest.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Tests\Feature\API;
+
+use App\Models\Project;
+use App\Models\TeamMember;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Tests\Feature\TestCase;
+
+class TeamMemberTest extends TestCase
+{
+    public function test_team_members_list()
+    {
+        TeamMember::factory(30)->create();
+
+        $response = $this->getJson(route('team-member.list', ['project' => Project::query()->first()->id]));
+
+        $response->assertStatus(200)
+            ->assertJsonStructure([
+                'data' => [
+                    '*' => [
+                        'id',
+                        'user',
+                        'user_id',
+                        'role',
+                        'limited',
+                        'join_at',
+                    ]
+                ]
+            ]);
+    }
+
+    public function test_team_member_delete(): void
+    {
+        $teamMember = TeamMember::factory()->create();
+
+        $response = $this->delete(route('team-member.destroy', ['team_member' => $teamMember->id]));
+
+        $response->assertStatus(204);
+
+        $this->assertNull(TeamMember::find($teamMember->id));
+    }
+}