From 268c696d64ff99510994be7966bcefe78c486588 Mon Sep 17 00:00:00 2001 From: lexx Date: Tue, 13 Jan 2026 17:51:19 +0200 Subject: [PATCH] files --- .../FieldEditEntry/FieldEditEntry.svelte | 3 + .../FieldEditEntry/FileFieldProps.svelte | 15 ++ .../entry/RecordEditEntry/RecordForm.svelte | 21 ++ .../RecordEditEntry/fields/FieldError.svelte | 10 + .../RecordEditEntry/fields/FieldLabel.svelte | 9 + .../RecordEditEntry/fields/FileField.svelte | 226 ++++++++++++++++++ .../fields/RelationField.svelte | 76 ++++-- .../RecordEditEntry/fields/TextField.svelte | 41 +--- front/js/modules/upload.js | 58 +++++ src/Core/Data/File.php | 16 ++ src/Core/Data/RecordFile.php | 14 ++ src/Core/File/FileModule.php | 38 +++ src/Core/File/RecordFileModule.php | 34 +++ src/Core/Record/RecordValidationModule.php | 107 ++++++++- src/Core/Repository/EdgeRepo.php | 21 ++ src/Core/Repository/FileRepo.php | 27 +++ src/Core/Repository/RecordFileRepo.php | 27 +++ src/Core/Repository/RecordRepo.php | 2 + src/Core/Schema/Data/FieldProp/FieldProp.php | 5 + .../Schema/Data/FieldProp/FileFieldProp.php | 6 + src/Edge/EdgeRepo.php | 28 +-- src/Http/Controller/EdgeController.php | 46 +++- src/Http/Controller/RecordController.php | 28 ++- src/Http/Controller/UploadController.php | 101 ++++++++ src/Http/web.php | 10 + 25 files changed, 889 insertions(+), 80 deletions(-) create mode 100644 front/js/entry/FieldEditEntry/FileFieldProps.svelte create mode 100644 front/js/entry/RecordEditEntry/fields/FieldError.svelte create mode 100644 front/js/entry/RecordEditEntry/fields/FieldLabel.svelte create mode 100644 front/js/entry/RecordEditEntry/fields/FileField.svelte create mode 100644 front/js/modules/upload.js create mode 100644 src/Core/Data/File.php create mode 100644 src/Core/Data/RecordFile.php create mode 100644 src/Core/File/FileModule.php create mode 100644 src/Core/File/RecordFileModule.php create mode 100644 src/Core/Repository/FileRepo.php create mode 100644 src/Core/Repository/RecordFileRepo.php create mode 100644 src/Core/Schema/Data/FieldProp/FileFieldProp.php create mode 100644 src/Http/Controller/UploadController.php diff --git a/front/js/entry/FieldEditEntry/FieldEditEntry.svelte b/front/js/entry/FieldEditEntry/FieldEditEntry.svelte index c34439d..331b126 100644 --- a/front/js/entry/FieldEditEntry/FieldEditEntry.svelte +++ b/front/js/entry/FieldEditEntry/FieldEditEntry.svelte @@ -2,6 +2,7 @@ import SchemaLayout from "../../layouts/SchemaLayout.svelte"; import TextFieldProps from "./TextFieldProps.svelte"; import RelationFieldProps from "./RelationFieldProps.svelte"; + import FileFieldProps from "./FileFieldProps.svelte"; import DeleteButton from "../../common/DeleteButton.svelte"; import { post } from "../../modules/remote"; import { getApp } from "../../app"; @@ -128,6 +129,8 @@ {:else if data.field.type === "relation"} + {:else if data.field.type === "file"} + {/if} diff --git a/front/js/entry/FieldEditEntry/FileFieldProps.svelte b/front/js/entry/FieldEditEntry/FileFieldProps.svelte new file mode 100644 index 0000000..e205c9e --- /dev/null +++ b/front/js/entry/FieldEditEntry/FileFieldProps.svelte @@ -0,0 +1,15 @@ + + +
+ + + +
diff --git a/front/js/entry/RecordEditEntry/RecordForm.svelte b/front/js/entry/RecordEditEntry/RecordForm.svelte index fe0c300..92a6f1a 100644 --- a/front/js/entry/RecordEditEntry/RecordForm.svelte +++ b/front/js/entry/RecordEditEntry/RecordForm.svelte @@ -1,6 +1,7 @@ + +{#if hasError} + {validationError.message} +{:else if schemaField.help != ""} + {schemaField.help} +{/if} diff --git a/front/js/entry/RecordEditEntry/fields/FieldLabel.svelte b/front/js/entry/RecordEditEntry/fields/FieldLabel.svelte new file mode 100644 index 0000000..7c88dbd --- /dev/null +++ b/front/js/entry/RecordEditEntry/fields/FieldLabel.svelte @@ -0,0 +1,9 @@ + + +{#if locale !== "main"} + {getLocaleName(channel, locale)} > +{/if} +{schemaField.name}
diff --git a/front/js/entry/RecordEditEntry/fields/FileField.svelte b/front/js/entry/RecordEditEntry/fields/FileField.svelte new file mode 100644 index 0000000..f43de6a --- /dev/null +++ b/front/js/entry/RecordEditEntry/fields/FileField.svelte @@ -0,0 +1,226 @@ + + +
+ + + + + +
+
+ +

+ Records +

+
+ {#if suggestionsLoaded} +
+ + + + {#each filesInProgress as fileInProgress} +
+ {fileInProgress.name} + + {#if fileInProgress.hasFailed} + Error + {/if} +
+ {/each} + + + + {#each suggestions as suggestion} + + + + + + {/each} + +
+ + + {suggestion.title} + + + {suggestion.schemaName} + +
+
+ {:else} + + {/if} +
+
+
+ {#if edgeRecordPreviews.length == 0} + No relations exist + {:else} + + {#snippet itemView(edgeRecordPreview)} +
+ {edgeRecordPreview.recordPreview.title} + {edgeRecordPreview.recordPreview.schemaName} + +
+ {/snippet} +
+ {/if} +
+
diff --git a/front/js/entry/RecordEditEntry/fields/RelationField.svelte b/front/js/entry/RecordEditEntry/fields/RelationField.svelte index 501f84b..32eec93 100644 --- a/front/js/entry/RecordEditEntry/fields/RelationField.svelte +++ b/front/js/entry/RecordEditEntry/fields/RelationField.svelte @@ -1,7 +1,9 @@ -
diff --git a/front/js/modules/upload.js b/front/js/modules/upload.js new file mode 100644 index 0000000..6cead7b --- /dev/null +++ b/front/js/modules/upload.js @@ -0,0 +1,58 @@ +import { getApp } from "../app"; + +export function uploadFile(file, recordId, fieldId, locale, progress, error) { + const app = getApp(); + const csrf = document.querySelector('meta[name="csrf-token"]').content; + const chunkSize = 2 * 1024 * 1024; // 2MB + const totalChunks = Math.ceil(file.size / chunkSize); + + // Start the recursive process + sendChunk(0, null); + + function sendChunk(currentChunk, fileId) { + const start = currentChunk * chunkSize; + const end = Math.min(start + chunkSize, file.size); + const chunk = file.slice(start, end); + + const formData = new FormData(); + formData.append("file", chunk); + if (fileId) { + formData.append("fileId", fileId); + } + + formData.append("recordId", recordId); + formData.append("fieldId", fieldId); + formData.append("isLast", currentChunk === totalChunks - 1); + formData.append("filename", file.name); + formData.append("locale", locale); + formData.append("_token", csrf); + + const xhr = new XMLHttpRequest(); + xhr.open("POST", app.url("upload"), true); + + // Success Callback + xhr.onload = function () { + if (xhr.status === 200) { + const response = JSON.parse(xhr.responseText); + let fileId = response.fileId; + const nextChunk = currentChunk + 1; + if (nextChunk < totalChunks) { + progress({ + pct: Math.round((nextChunk / totalChunks) * 100), + isComplete: false, + }); + sendChunk(nextChunk, fileId); + } else { + progress({ + pct: 100, + isComplete: true, + }); + } + } else { + error("Upload failed at chunk " + currentChunk); + } + }; + + xhr.send(formData); + } +} diff --git a/src/Core/Data/File.php b/src/Core/Data/File.php new file mode 100644 index 0000000..cd6e935 --- /dev/null +++ b/src/Core/Data/File.php @@ -0,0 +1,16 @@ + $file->id, + "name" => $file->name, + "size" => $file->size, + "width" => $file->width, + "height" => $file->height, + "mime" => $file->mime, + "checksum" => $file->checksum, + "record_id" => $file->recordId, + "is_shared" => $file->isShared, + ]; + } + + public static function fromDb(stdClass $data): File + { + return new File( + id: data_get($data, "id"), + name: data_get($data, "name"), + size: data_get($data, "size"), + width: data_get($data, "width"), + height: data_get($data, "height"), + mime: data_get($data, "mime"), + checksum: data_get($data, "checksum"), + recordId: data_get($data, "recordId"), + isShared: data_get($data, "isShared"), + ); + } +} diff --git a/src/Core/File/RecordFileModule.php b/src/Core/File/RecordFileModule.php new file mode 100644 index 0000000..38d8c47 --- /dev/null +++ b/src/Core/File/RecordFileModule.php @@ -0,0 +1,34 @@ + $file->id, + "record_id" => $file->recordId, + "file_id" => $file->fileId, + "field_id" => $file->fieldId, + "mode" => $file->mode, + "locale" => $file->locale, + "rank" => $file->rank, + ]; + } + + public static function fromDb(stdClass $data): RecordFile + { + return new RecordFile( + id: data_get($data, "id"), + recordId: data_get($data, "recordId"), + fileId: data_get($data, "file_id"), + fieldId: data_get($data, "field_id"), + mode: RecordMode::from(data_get($data, "mode")), + locale: data_get($data, "locale"), + rank: data_get($data, "rank"), + ); + } +} diff --git a/src/Core/Record/RecordValidationModule.php b/src/Core/Record/RecordValidationModule.php index 5bde0d6..18c7f42 100644 --- a/src/Core/Record/RecordValidationModule.php +++ b/src/Core/Record/RecordValidationModule.php @@ -14,16 +14,23 @@ class RecordValidationModule * @param string[] $locales * @param Field[] $schemaFields * @param RecordField[] $recordFields + * @param Edge[] $recordEdges * @return RecordError[] */ public static function validate( array $locales, array $schemaFields, array $recordFields, + array $recordEdges, ): array { $errors = []; foreach ($schemaFields as $schemaField) { - $res = static::validateField("main", $schemaField, $recordFields); + $res = static::validateField( + "main", + $schemaField, + $recordFields, + $recordEdges, + ); $errors[] = $res; if ($schemaField->translatable) { foreach ($locales as $locale) { @@ -31,6 +38,7 @@ class RecordValidationModule $locale["id"], $schemaField, $recordFields, + $recordEdges, ); $errors[] = $res; } @@ -47,25 +55,39 @@ class RecordValidationModule * * @param Field $schemaField * @param RecordField[] $recordFields + * @param Edge[] $recordEdges * @return array */ public static function validateField( string $locale, Field $schemaField, array $recordFields, + array $recordEdges, ): ?RecordError { // General Validations - $error = static::validateRequired($locale, $schemaField, $recordFields); + $error = static::validateRequired( + $locale, + $schemaField, + $recordFields, + $recordEdges, + ); + if (!empty($error)) { return $error; } // Type specific + $error = match ($schemaField->type) { "text" => static::validateText( $locale, $schemaField, $recordFields, ), + "relation" => static::validateRelation( + $locale, + $schemaField, + $recordEdges, + ), default => static::validateText( $locale, $schemaField, @@ -80,16 +102,37 @@ class RecordValidationModule * * @param Field $schemaField * @param RecordField[] $recordFields + * @param Edge[] $recordEdges * @return ?RecordError */ public static function validateRequired( string $locale, Field $schemaField, array $recordFields, + array $recordEdges, ): ?RecordError { if ($schemaField->required === false) { return null; } + return match ($schemaField->type) { + "relation" => static::validateRequiredRelation( + $locale, + $schemaField, + $recordEdges, + ), + default => static::validateRequiredField( + $locale, + $schemaField, + $recordFields, + ), + }; + } + + private static function validateRequiredField( + string $locale, + Field $schemaField, + array $recordFields, + ): ?RecordError { $recordField = static::findField($recordFields, $schemaField, $locale); if (empty($recordField) || empty($recordField->value)) { @@ -102,6 +145,27 @@ class RecordValidationModule return null; } + private static function validateRequiredRelation( + string $locale, + Field $schemaField, + array $recordEdges, + ): ?RecordError { + if ( + collect($recordEdges) + ->where("fieldId", $schemaField->id) + ->where("locale", $locale) + ->where("mode", RecordMode::DRAFT) + ->isEmpty() + ) { + return new RecordError( + $schemaField->id, + $locale, + "This field is required", + ); + } + + return null; + } /** * @@ -151,6 +215,45 @@ class RecordValidationModule return null; } + /** + * + * @param Field $schemaField + * @param Edge[] $recordEdges + * @return ?RecordError + */ + public static function validateRelation( + string $locale, + Field $schemaField, + array $recordEdges, + ): ?RecordError { + $count = collect($recordEdges) + ->where("fieldId", $schemaField->id) + ->where("locale", $locale) + ->where("mode", RecordMode::DRAFT) + ->count(); + + if ($schemaField->props->min > 0) { + if ($count < $schemaField->props->min) { + return new RecordError( + $schemaField->id, + $locale, + "You have to have at least {$schemaField->props->min} related records", + ); + } + } + if ($schemaField->props->max > 0) { + if ($count > $schemaField->props->max) { + return new RecordError( + $schemaField->id, + $locale, + "You have to have at most {$schemaField->props->max} related records", + ); + } + } + + return null; + } + private static function findField( array $recordFields, Field $schemaField, diff --git a/src/Core/Repository/EdgeRepo.php b/src/Core/Repository/EdgeRepo.php index 7c8e674..dc43a4d 100644 --- a/src/Core/Repository/EdgeRepo.php +++ b/src/Core/Repository/EdgeRepo.php @@ -29,6 +29,11 @@ class EdgeRepo ->delete(); } + public static function delete(string $id): void + { + DB::table(self::TABLE_NAME)->where("id", $id)->delete(); + } + /** * @return Edge[] */ @@ -41,6 +46,22 @@ class EdgeRepo ->toArray(); } + /** + * @return ?Edge + */ + public static function findOne(string $id): ?Edge + { + $edges = DB::table(self::TABLE_NAME)->where("id", $id)->get(); + return $edges->map(EdgeModule::fromDb(...))->first(); + } + + public static function update(Edge $edge): void + { + DB::table(self::TABLE_NAME) + ->where("id", $edge->id) + ->update(EdgeModule::toDb($edge)); + } + public static function findLastOfField( string $from, string $fieldId, diff --git a/src/Core/Repository/FileRepo.php b/src/Core/Repository/FileRepo.php new file mode 100644 index 0000000..8829136 --- /dev/null +++ b/src/Core/Repository/FileRepo.php @@ -0,0 +1,27 @@ +insert(FileModule::toDb($file)); + } + + // public static function update(File $file): void + // { + // DB::table(self::TABLE_NAME) + // ->where("id", $file->id) + // ->update(FileModule::toDb($file)); + // } + + public static function delete(string $fileId): void + { + DB::table(self::TABLE_NAME)->where("id", $fileId)->delete(); + } +} diff --git a/src/Core/Repository/RecordFileRepo.php b/src/Core/Repository/RecordFileRepo.php new file mode 100644 index 0000000..f49b0ab --- /dev/null +++ b/src/Core/Repository/RecordFileRepo.php @@ -0,0 +1,27 @@ +insert(RecordFileModule::toDb($file)); + } + + // public static function update(File $file): void + // { + // DB::table(self::TABLE_NAME) + // ->where("id", $file->id) + // ->update(FileModule::toDb($file)); + // } + + public static function delete(string $fileId): void + { + DB::table(self::TABLE_NAME)->where("id", $fileId)->delete(); + } +} diff --git a/src/Core/Repository/RecordRepo.php b/src/Core/Repository/RecordRepo.php index bef1a2f..c5c9974 100644 --- a/src/Core/Repository/RecordRepo.php +++ b/src/Core/Repository/RecordRepo.php @@ -71,6 +71,7 @@ class RecordRepo ->where("records_data.mode", RecordMode::DRAFT->value) ->orderBy("created_at", "desc") ->limit(5) + ->distinct() ->get() ->map(fn($row) => RecordModule::recordPreviewFromDb($schemas, $row)) ->toArray(); @@ -147,6 +148,7 @@ class RecordRepo ); }) ->orderBy("edges.rank", "asc") + ->distinct() ->get() ->map( diff --git a/src/Core/Schema/Data/FieldProp/FieldProp.php b/src/Core/Schema/Data/FieldProp/FieldProp.php index 27022c8..c94aa15 100644 --- a/src/Core/Schema/Data/FieldProp/FieldProp.php +++ b/src/Core/Schema/Data/FieldProp/FieldProp.php @@ -7,6 +7,7 @@ class FieldProp return match ($type) { "text" => new TextFieldProp(min: 0, max: 0, default: ""), "relation" => new RelationFieldProp(schemas: [], min: 0, max: 0), + "file" => new FileFieldProp(min: 0, max: 0), default => new InvalidFieldProp(), }; } @@ -30,6 +31,10 @@ class FieldProp min: $props["min"] ?? 0, max: $props["max"] ?? 0, ), + "file" => new FileFieldProp( + min: $props["min"] ?? 0, + max: $props["max"] ?? 0, + ), default => new InvalidFieldProp(), }; } diff --git a/src/Core/Schema/Data/FieldProp/FileFieldProp.php b/src/Core/Schema/Data/FieldProp/FileFieldProp.php new file mode 100644 index 0000000..33080cb --- /dev/null +++ b/src/Core/Schema/Data/FieldProp/FileFieldProp.php @@ -0,0 +1,6 @@ +table("edges")->insert($edgesDB); } - /** * @return list */ public function findAll(): array { $edges = Database::make()->table("edges")->get(); - return $edges->map([$this, 'mapEdge'])->toArray(); + return $edges->map([$this, "mapEdge"])->toArray(); } public function findForSource(string $recordId): array { - $edges = Database::make()->table("edges")->where("source", $recordId)->get(); - return $edges->map([$this, 'mapEdge'])->toArray(); + $edges = Database::make() + ->table("edges") + ->where("source", $recordId) + ->get(); + return $edges->map([$this, "mapEdge"])->toArray(); } public function mapEdge(stdClass $edge): Edge { - return new Edge( source: $edge->source, target: $edge->target, @@ -82,14 +78,14 @@ class EdgeRepo targetSchema: $edge->targetSchema, field: $edge->field, rank: $edge->rank, - depth: $edge->depth ?? 0 + depth: $edge->depth ?? 0, ); - } public function remove(Edge $edge): void { - Database::make()->table("edges") + Database::make() + ->table("edges") ->where("source", $edge->source) ->where("target", $edge->target) ->where("sourceSchema", $edge->sourceSchema) @@ -100,7 +96,8 @@ class EdgeRepo public function findLastEdgeRank(string $source, string $field): string { - $data = Database::make()->table("edges") + $data = Database::make() + ->table("edges") ->where("source", $source) ->where("field", $field) ->orderBy("rank", "desc") @@ -108,5 +105,4 @@ class EdgeRepo return $data->rank ?? ""; } - } diff --git a/src/Http/Controller/EdgeController.php b/src/Http/Controller/EdgeController.php index 94fba61..a9892b8 100644 --- a/src/Http/Controller/EdgeController.php +++ b/src/Http/Controller/EdgeController.php @@ -7,14 +7,17 @@ use Illuminate\Http\Request; use Lucent\Core\Repository\EdgeRepo; use Lucent\Core\Repository\SchemaRepo; use Lucent\Core\Repository\RecordRepo; +use Lucent\Core\Repository\FieldRepo; use Lucent\Core\Data\Edge; use Lucent\Core\Data\RecordMode; use Lucent\Id\Id; +use Lucent\Core\Record\RecordValidationModule; use function Lucent\Response\fail; use function Lucent\Response\ok; class EdgeController extends Controller { + // Inserts edges to record, maybe I should move that to RecordController public function postCreateMany(Request $request) { $from = $request->input("from"); @@ -46,7 +49,48 @@ class EdgeController extends Controller $locale, $from, ); + $field = FieldRepo::findOne($fieldId); - return ok($edgeRecordPreviews); + $recordEdges = array_map(fn($e) => $e->edge, $edgeRecordPreviews); + $validationError = RecordValidationModule::validateField( + $locale, + $field, + [], + $recordEdges, + ); + + return ok([ + "edgeRecordPreviews" => $edgeRecordPreviews, + "validationError" => $validationError, + ]); + } + + public function postDelete(Request $request) + { + $id = $request->input("id"); + $fieldId = $request->input("fieldId"); + $locale = $request->input("locale"); + $from = $request->input("from"); + EdgeRepo::delete($id); + $schemas = SchemaRepo::all(); + $edgeRecordPreviews = RecordRepo::findEdgeRecordPreviewsForField( + $schemas, + $fieldId, + $locale, + $from, + ); + $field = FieldRepo::findOne($fieldId); + + $recordEdges = array_map(fn($e) => $e->edge, $edgeRecordPreviews); + $validationError = RecordValidationModule::validateField( + $locale, + $field, + [], + $recordEdges, + ); + + return ok([ + "validationError" => $validationError, + ]); } } diff --git a/src/Http/Controller/RecordController.php b/src/Http/Controller/RecordController.php index 19856b0..8b01568 100644 --- a/src/Http/Controller/RecordController.php +++ b/src/Http/Controller/RecordController.php @@ -11,6 +11,7 @@ use Lucent\Core\Data\RecordField; use Lucent\Core\Query\QueryModule; use Lucent\Core\Repository\FieldRepo; use Lucent\Core\Repository\SchemaRepo; +use Lucent\Core\Repository\EdgeRepo; use Lucent\Core\Repository\RecordFieldRepo; use Lucent\Core\Record\RecordModule; use Lucent\Core\Record\RecordFieldModule; @@ -190,12 +191,6 @@ class RecordController $fields = FieldRepo::findBySchemaId($record->schemaId); $locales = ChannelModule::get()->locales; - $validationErrors = RecordValidationModule::validate( - $locales, - $fields, - $draftData, - ); - $recordStatus = RecordModule::getStatus($record); $edgeRecordPreviews = RecordRepo::findEdgeRecordPreviewsByRecordId( $schemas, @@ -210,6 +205,13 @@ class RecordController ->where("edge.mode", RecordMode::LIVE) ->values() ->toArray(); + $recordEdges = array_map(fn($e) => $e->edge, $edgeRecordPreviewsDraft); + $validationErrors = RecordValidationModule::validate( + $locales, + $fields, + $draftData, + $recordEdges, + ); return Svelte::view( view: "recordEdit", @@ -306,6 +308,7 @@ class RecordController $locale, $field, [$recordField], + [], ); return ok([ @@ -314,6 +317,19 @@ class RecordController ]); } + public function postSortEdges(Request $request) + { + $edgeIds = $request->input("ids"); + foreach ($edgeIds as $index => $id) { + $edge = EdgeRepo::findOne($id); + if ($edge) { + $edge->rank = $index; + EdgeRepo::update($edge); + } + } + return response()->json(["ids" => $edgeIds], 200); + } + public function clone(Request $request) { try { diff --git a/src/Http/Controller/UploadController.php b/src/Http/Controller/UploadController.php new file mode 100644 index 0000000..6269633 --- /dev/null +++ b/src/Http/Controller/UploadController.php @@ -0,0 +1,101 @@ +hasFile("file")) { + return response()->json(["error" => "No file provided"], 400); + } + + $file = $request->file("file"); + $fileId = $request->input("fileId") ?? Id::new(); + + $filename = $request->input("filename"); + $isLast = $request->input("isLast") === "true"; + $recordId = $request->input("recordId"); + $fieldId = $request->input("fieldId"); + $locale = $request->input("locale"); + + // 2. Define path (e.g., storage/app/chunks/myvideo.mp4) + $extension = $extension = pathinfo($filename, PATHINFO_EXTENSION); + $tempPath = "chunks/" . $fileId . "." . $extension; + $fullTempPath = Storage::disk("local")->path($tempPath); + // 3. Append the raw chunk data to the file + // This creates the file if it doesn't exist, or adds to it if it does. + Storage::disk("local")->append( + $tempPath, + file_get_contents($file->getRealPath()), + null, + ); + + // 4. Finalize + if ($isLast) { + $dimensions = getimagesize($fullTempPath); + $width = $dimensions[0] ?? 0; + $height = $dimensions[1] ?? 0; + + $file = new File( + id: $fileId, + name: $filename, + size: Storage::disk("local")->size($tempPath), + width: $width, + height: $height, + mime: Storage::disk("local")->mimeType($tempPath), + checksum: hash_file("md5", $fullTempPath), + recordId: $recordId, + isShared: false, + ); + + $finalPath = "uploads/" . $fileId . "." . $extension; + Storage::disk("local")->move($tempPath, $finalPath); + + FileRepo::insert($file); + + $recordFile = new RecordFile( + id: Id::new(), + recordId: $recordId, + fileId: $fileId, + fieldId: $fieldId, + mode: RecordMode::DRAFT, + locale: $locale, + rank: 0, + ); + RecordFileRepo::insert($recordFile); + + return response()->json([ + "status" => "finished", + "fileId" => $fileId, + "location" => Storage::url($finalPath), + ]); + } + + return response()->json([ + "status" => "chunk_saved", + "fileId" => $fileId, + ]); + } +} diff --git a/src/Http/web.php b/src/Http/web.php index 599a721..1d11325 100644 --- a/src/Http/web.php +++ b/src/Http/web.php @@ -8,6 +8,7 @@ use Lucent\Http\Controller\EdgeController; use Lucent\Http\Controller\FieldController; use Lucent\Http\Controller\FileController; use Lucent\Http\Controller\HomeController; +use Lucent\Http\Controller\UploadController; use Lucent\Http\Controller\MemberController; use Lucent\Http\Controller\RecordController; use Lucent\Http\Controller\RevisionController; @@ -99,11 +100,20 @@ Route::group( "untrash", ]); + Route::post("records/sort-edges", [ + RecordController::class, + "postSortEdges", + ]); + // EDGES Route::post("edges/many", [ EdgeController::class, "postCreateMany", ]); + Route::post("edges/delete", [EdgeController::class, "postDelete"]); + + // UPLOAD + Route::post("upload", [UploadController::class, "upload"]); }); //OLD