Просмотр исходного кода

Merge branch 'asset-groups' of kyle/autocde2.0 into dev

Mo 1 год назад
Родитель
Сommit
9366981ff1

+ 71 - 0
app/Http/Controllers/API/AssetGroupController.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace App\Http\Controllers\API;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\API\AssetGroup\CreateOrUpdateRequest;
+use App\Http\Resources\API\AssetGroupResource;
+use App\Models\AssetGroup;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class AssetGroupController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     */
+    public function index()
+    {
+        $groups = AssetGroup::query()->orderByDesc("sequence")->get();
+
+        return AssetGroupResource::collection($groups);
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     */
+    public function store(CreateOrUpdateRequest $request)
+    {
+        AssetGroup::create([
+            ...$request->all(),
+            'company_id' => Auth::user()->company_id,
+        ]);
+
+        return $this->created();
+    }
+
+    /**
+     * Display the specified resource.
+     */
+    public function show(string $id)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     */
+    public function update(CreateOrUpdateRequest $request, string $id)
+    {
+        $group = AssetGroup::query()->findOrFail($id);
+
+        $group->fill($request->only(
+            'name', 'sequence'
+        ));
+        $group->save();
+
+        return $this->noContent();
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     */
+    public function destroy(string $id)
+    {
+        $group = AssetGroup::query()->findOrFail($id);
+
+        $group->delete();
+
+        return $this->noContent();
+    }
+}

+ 2 - 2
app/Http/Controllers/JsonResponseHelper.php

@@ -11,9 +11,9 @@ trait JsonResponseHelper
      * 201
      *
      * @param array|string|null $content
-     * @return string
+     * @return Response
      */
-    protected function created(array|string $content = null): string
+    protected function created(array|string $content = null): Response
     {
         return new Response($content, Response::HTTP_CREATED);
     }

+ 37 - 0
app/Http/Requests/API/AssetGroup/CreateOrUpdateRequest.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Http\Requests\API\AssetGroup;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class CreateOrUpdateRequest 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 [
+            'name' => 'required|max:100',
+            'sequence' => 'numeric',
+        ];
+    }
+
+    public function attributes(): array
+    {
+        return [
+            'name' => __("fields.name"),
+            'sequence' => __("fields.sequence"),
+        ];
+    }
+}

+ 25 - 0
app/Http/Resources/API/AssetGroupResource.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class AssetGroupResource 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,
+            'sequence' => $this->sequence,
+            'created_at' => (string) $this->created_at,
+            'updated_at' => (string) $this->updated_at,
+        ];
+    }
+}

+ 24 - 0
app/Models/AssetGroup.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Models;
+
+use App\Models\Scopes\CompanyScope;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class AssetGroup extends Model
+{
+    use HasFactory, SoftDeletes;
+
+    protected $fillable = [
+        'company_id',
+        'name',
+        'sequence'
+    ];
+
+    protected static function booted(): void
+    {
+        static::addGlobalScope(new CompanyScope);
+    }
+}

+ 17 - 0
app/Models/Scopes/CompanyScope.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models\Scopes;
+
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Scope;
+use Illuminate\Support\Facades\Auth;
+
+
+class CompanyScope implements Scope
+{
+    public function apply(Builder $builder, Model $model): void
+    {
+        $builder->where('company_id', '=', Auth::user()->company_id);
+    }
+}

+ 26 - 0
database/factories/AssetGroupFactory.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Database\Factories;
+
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\AssetGroup>
+ */
+class AssetGroupFactory extends Factory
+{
+    /**
+     * Define the model's default state.
+     *
+     * @return array<string, mixed>
+     */
+    public function definition(): array
+    {
+        return [
+            'name' => fake()->name(),
+            'sequence' => fake()->randomNumber(1, 9),
+            'company_id' => Auth::user()->company_id,
+        ];
+    }
+}

+ 31 - 0
database/migrations/2024_01_16_142814_create_asset_groups_table.php

@@ -0,0 +1,31 @@
+<?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('asset_groups', function (Blueprint $table) {
+            $table->id();
+            $table->integer('company_id')->index();
+            $table->string('name', 100);
+            $table->integer('sequence')->default(0);
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('asset_groups');
+    }
+};

+ 9 - 0
lang/en/fields.php

@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+return [
+    'company_id' => 'Company ID',
+    'name'  => 'Name',
+    'sequence'  => 'Sequence',
+];

+ 9 - 0
lang/zh_CN/fields.php

@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+return [
+    'company_id' => '公司ID',
+    'name'  => '名字',
+    'sequence'  => '排序',
+];

+ 9 - 0
lang/zh_TW/fields.php

@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+return [
+    'company_id' => '公司ID',
+    'name'  => '名字',
+    'sequence'  => '排序',
+];

+ 8 - 2
routes/api.php

@@ -2,6 +2,7 @@
 
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\API;
 
 /*
 |--------------------------------------------------------------------------
@@ -14,12 +15,17 @@ use Illuminate\Support\Facades\Route;
 |
 */
 
+
 Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
     return $request->user();
 });
 
-Route::post("/login", [\App\Http\Controllers\API\AuthController::class, "login"]);
+Route::post("/login", [API\AuthController::class, "login"]);
 
 Route::middleware(['auth:sanctum'])->group(function () {
-    Route::post("/logout", [\App\Http\Controllers\API\AuthController::class, "logout"]);
+    Route::post("/logout", [API\AuthController::class, "logout"]);
+
+    Route::apiResources([
+        'asset-group' => API\AssetGroupController::class,
+    ]);
 });

+ 64 - 0
tests/Feature/API/AssetGroupTest.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace Tests\Feature\API;
+
+
+use App\Models\AssetGroup;
+use Tests\Feature\TestCase;
+
+class AssetGroupTest extends TestCase
+{
+    public function test_asset_group_list()
+    {
+        AssetGroup::factory(30)->create();
+
+        $response = $this->get(route('asset-group.index'));
+
+        $response->assertStatus(200)
+            ->assertJsonStructure([
+                'data' => [
+                    '*' => [
+                        'name',
+                        'sequence'
+                    ]
+                ]
+            ]);
+    }
+
+    public function test_asset_group_create(): void
+    {
+        $response = $this->post(route('asset-group.store'), [
+            'name' => 'test',
+            'sequence' => 1,
+        ]);
+
+        $response->assertStatus(201);
+    }
+
+    public function test_asset_group_update(): void
+    {
+        $assetGroup = AssetGroup::factory()->create();
+
+        $response = $this->put(route('asset-group.update', ['asset_group' => $assetGroup->id]), [
+            'name' => 'test',
+            'sequence' => 1,
+        ]);
+
+        $response->assertStatus(204);
+
+        $newAssetGroup = AssetGroup::find($assetGroup->id);
+        $this->assertEquals('test', $newAssetGroup->name);
+        $this->assertEquals(1, $newAssetGroup->sequence);
+    }
+
+    public function test_asset_group_delete(): void
+    {
+        $assetGroup = AssetGroup::factory()->create();
+
+        $response = $this->delete(route('asset-group.destroy', ['asset_group' => $assetGroup->id]));
+
+        $response->assertStatus(204);
+
+        $this->assertNull(AssetGroup::find($assetGroup->id));
+    }
+}

+ 49 - 0
tests/Feature/TestCase.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace Tests\Feature;
+
+
+use App\Models\User;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Laravel\Sanctum\Sanctum;
+
+class TestCase extends \Tests\TestCase
+{
+    use RefreshDatabase, WithFaker;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $user = User::factory()->create([
+            'username' => 'lpc',
+            'email' => 'test@lpc.com',
+            'company_id' => 1,
+        ]);
+
+        Sanctum::actingAs($user);
+    }
+
+    protected function simplePaginateResponseStructure(array $data): array
+    {
+        return [
+            'data' => [
+                '*' => $data
+            ],
+            'links' => [
+                'first',
+                'last',
+                'prev',
+                'next',
+            ],
+            'meta' => [
+                'current_page',
+                'from',
+                'path',
+                'per_page',
+                'to',
+            ]
+        ];
+    }
+}