Quellcode durchsuchen

batch file upload

moell vor 11 Monaten
Ursprung
Commit
a9e9740cd2

+ 55 - 0
app/Http/Controllers/API/FileController.php

@@ -4,8 +4,13 @@ namespace App\Http\Controllers\API;
 
 use App\Http\Controllers\Controller;
 use App\Http\Requests\API\File\DownloadRequest;
+use App\Http\Requests\API\File\FileUploadRequest;
 use App\Http\Requests\API\File\UploadRequest;
+use App\Http\Resources\API\FileUploadSuccessResource;
+use App\Models\Enums\FileObjectType;
+use App\Models\File;
 use Carbon\Carbon;
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Storage;
 use Illuminate\Support\Str;
 
@@ -35,5 +40,55 @@ class FileController extends Controller
         return Storage::download($url);
     }
 
+    /**
+     * 文件上传
+     *
+     * @param FileUploadRequest $request
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function uploads(FileUploadRequest $request)
+    {
+        $names = $request->get("file_names", []);
+        $fileObjectType = FileObjectType::from($request->object_type);
+
+        foreach ($request->file("files") as $file) {
+            if (! $file->isValid()) {
+                return $this->badRequest("File upload failed.");
+            }
+        }
+
+        $items = [];
+        foreach ($request->file("files") as $index => $file) {
+            $pathname = $file->storeAs(
+                sprintf("c%s/%s/%s", Auth::user()->company_id, $fileObjectType->value, date("Ymd")),
+                sprintf("%s.%s", md5(uniqid()), $file->extension()),
+            );
+
+            if (! $pathname) {
+                return $this->badRequest("File upload failed.");
+            }
 
+            $items[] = [
+                'pathname' => $pathname,
+                'title' => $names[$index] ?? $file->getClientOriginalName(),
+                'size' => $file->getSize(),
+                'extension' => $file->extension(),
+                'object_type' => $request->object_type,
+                'object_id' => $request->object_id,
+                'created_by' => Auth::id(),
+                'company_id' => Auth::user()->company_id,
+            ];
+        }
+
+        $uploadedFiles = [];
+        foreach ($items as $item) {
+            $file = File::query()->create($item);
+
+            $uploadedFiles[] = new FileUploadSuccessResource($file);
+        }
+
+        return $this->success([
+            'data' => $uploadedFiles
+        ]);
+    }
 }

+ 53 - 0
app/Http/Requests/API/File/FileUploadRequest.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Http\Requests\API\File;
+
+use App\Models\Enums\FileObjectType;
+use App\Models\User;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Validation\Rules\Enum;
+use Illuminate\Validation\Rules\File;
+
+class FileUploadRequest 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 [
+            "files.*" => [
+                'required',
+                File::types(['txt', 'jpeg', 'png', 'gif', 'pdf', 'xls', 'xlsx', 'zip', 'wps', 'docx', 'doc'])
+                    ->max("1gb"),
+            ],
+            "object_type" => [
+                'required',
+                new Enum(FileObjectType::class),
+            ],
+            "object_id" => [
+                function ($attribute, $value, $fail) {
+                    $exist = FileObjectType::from($this->get("object_type"))
+                        ->modelBuilderAllowed($value)
+                        ->where("company_id", Auth::user()->company_id)
+                        ->where('id', $value)
+                        ->count();
+                    if (! $exist) {
+                        $fail('Resources without permission to access.');
+                    }
+                }
+            ]
+        ];
+    }
+}

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

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Http\Resources\API;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Support\Facades\Storage;
+
+class FileUploadSuccessResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'title' => $this->title,
+            'url' => Storage::url($this->pathname),
+            'extension' => $this->extension,
+            'size' => $this->extension,
+        ];
+    }
+}

+ 34 - 0
app/Models/Enums/FileObjectType.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Models\Enums;
+
+use App\Models\Project;
+use App\Models\Requirement;
+use App\Models\Task;
+
+enum FileObjectType: string
+{
+    case PROJECT = "project";
+
+    case REQUIREMENT="requirement";
+
+    case TASK = "task";
+
+    public function modelBuilder(): \Illuminate\Database\Eloquent\Builder
+    {
+        return match ($this) {
+            self::PROJECT => Project::query(),
+            self::TASK => Task::query(),
+            self::REQUIREMENT => Requirement::query(),
+        };
+    }
+
+    public function modelBuilderAllowed(string $id = null): \Illuminate\Database\Eloquent\Builder
+    {
+        return match ($this) {
+            self::PROJECT => Project::query()->allowed($id),
+            self::TASK => Task::query()->allowed($id),
+            self::REQUIREMENT => Requirement::query(),
+        };
+    }
+}

+ 14 - 0
app/Models/File.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class File extends Model
+{
+    use HasFactory, SoftDeletes;
+
+    protected $guarded = ['id'];
+}

+ 38 - 0
database/migrations/2024_03_26_201122_create_files_table.php

@@ -0,0 +1,38 @@
+<?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('files', function (Blueprint $table) {
+            $table->id();
+            $table->integer("company_id")->index();
+            $table->string("pathname", 100);
+            $table->string("title");
+            $table->string("extension", 30);
+            $table->integer("size")->default(0);
+            $table->string("object_type", 30)->nullable();
+            $table->integer("object_id")->nullable();
+            $table->integer("created_by")->nullable();
+            $table->smallInteger("version")->default(1);
+            $table->integer("downloads")->default(0);
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('files');
+    }
+};

+ 2 - 0
routes/api.php

@@ -127,5 +127,7 @@ Route::middleware(['auth:sanctum'])->group(function () {
         Route::get("action/{object_type}/history/{object_id}", [API\ActionController::class, "history"])->name("action.history");
         Route::post("action/{object_type}/comment/{object_id}", [API\ActionController::class, "comment"])->name("action.comment");
         Route::patch("action/{action}/comment", [API\ActionController::class, "updateComment"])->name("action.update-comment");
+
+        Route::post("file-upload", [API\FileController::class, "uploads"])->name("file.upload");
     });
 });