diff --git a/app/Http/Controllers/Entity/AssetController.php b/app/Http/Controllers/Entity/AssetController.php index 55451ab2d..3f22ca0b7 100644 --- a/app/Http/Controllers/Entity/AssetController.php +++ b/app/Http/Controllers/Entity/AssetController.php @@ -30,7 +30,7 @@ public function index(Campaign $campaign, Entity $entity) ); } - $assets = $entity->assets; + $assets = $entity->assets()->with('image')->get(); return view('entities.pages.assets.index', compact( 'campaign', @@ -102,7 +102,7 @@ protected function storeFile(StoreEntityAsset $request, Campaign $campaign, Enti $file = $service ->entity($entity) ->campaign($campaign) - ->upload($request, 'file', 'w/' . $campaign->id . '/entity-assets'); + ->upload($request, 'file'); return redirect() ->route('entities.entity_assets.index', [$campaign, $entity]) diff --git a/app/Models/EntityAsset.php b/app/Models/EntityAsset.php index 7ad7c3999..136d68a1f 100644 --- a/app/Models/EntityAsset.php +++ b/app/Models/EntityAsset.php @@ -16,17 +16,20 @@ use Illuminate\Support\Arr; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; +use Illuminate\Database\Eloquent\Relations\HasOne; /** * @property int $id * @property int $type_id * @property int $entity_id + * @property string|null $image_uuid * @property string $name * @property array $metadata * @property Carbon $created_at * @property Carbon $updated_at * @property Entity|null $entity * @property bool $is_pinned + * @property ?Image $image * */ class EntityAsset extends Model @@ -49,6 +52,7 @@ class EntityAsset extends Model 'metadata', 'visibility_id', 'is_pinned', + 'image_uuid', ]; public $casts = [ @@ -104,6 +108,10 @@ public function isImage(): bool */ public function imageUrl(): string { + if ($this->image) { + return $this->image->getUrl(120, 80); + } + return Img::crop(120, 80)->url($this->metadata['path']); } @@ -128,6 +136,10 @@ public function getIconAttribute(): mixed */ public function getImagePathAttribute(): string { + if ($this->image && !$this->image->isUsed()) { + return (string) $this->image->path; + } + return (string) $this->metadata['path']; } @@ -157,6 +169,10 @@ public function urlDomain(): string public function url(): string { + if ($this->image_uuid) { + return $this->image->url(); + } + $path = $this->metadata['path']; $cloudfront = config('filesystems.disks.cloudfront.url'); if ($cloudfront) { @@ -164,4 +180,12 @@ public function url(): string } return Storage::url($path); } + + /** + * Image stored in the gallery + */ + public function image(): HasOne + { + return $this->hasOne('App\Models\Image', 'id', 'image_uuid'); + } } diff --git a/app/Models/Image.php b/app/Models/Image.php index 8c5533397..082455bae 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -117,6 +117,12 @@ public function inventories(): HasMany return $this->hasMany(Inventory::class, 'image_uuid', 'id'); } + public function entityAssets(): HasMany + { + return $this->hasMany(EntityAsset::class, 'image_uuid', 'id') + ->with('entity'); + } + public function headers(): HasMany { return $this->hasMany(Entity::class, 'header_uuid', 'id'); @@ -150,10 +156,26 @@ public function inEntities(): array } $entities[$entity->id] = $entity; } + foreach ($this->entityAssets as $asset) { + if (isset($entities[$asset->entity->id])) { + continue; + } + $entities[$asset->entity->id] = $asset->entity; + } return $entities; } + public function isUsed(): bool + { + $entities = count($this->inEntities()); + $mentions = $this->mentions()->count(); + $layers = $this->mapLayers()->count(); + $inventories = $this->inventories()->count(); + + return $entities || $mentions || $layers || $inventories; + } + public function inEntitiesCount(): int { if (isset($this->_usageCount)) { @@ -282,6 +304,11 @@ public function isFont(): bool return in_array($this->ext, ['woff', 'woff2']); } + public function hasThumbnail(): bool + { + return in_array($this->ext, ['jpg', 'png', 'jpeg', 'gif', 'webp']); + } + public function getUrl(?int $sizeX = null, ?int $sizeY = null): string { if ($this->isSvg()) { diff --git a/app/Models/Relations/EntityRelations.php b/app/Models/Relations/EntityRelations.php index 171e0b11e..b7f953918 100644 --- a/app/Models/Relations/EntityRelations.php +++ b/app/Models/Relations/EntityRelations.php @@ -293,6 +293,7 @@ public function pinnedFiles(): HasMany { return $this->files() ->where('is_pinned', 1) + ->with('image') ; } diff --git a/app/Services/Caches/CharacterCacheService.php b/app/Services/Caches/CharacterCacheService.php index dbc89a591..87fb0d74d 100644 --- a/app/Services/Caches/CharacterCacheService.php +++ b/app/Services/Caches/CharacterCacheService.php @@ -41,6 +41,7 @@ public function clearSuggestion(): self $this->forget( $this->genderSuggestionKey() ); + return $this; } diff --git a/app/Services/Campaign/ExportService.php b/app/Services/Campaign/ExportService.php index 207da086f..2fe25121d 100644 --- a/app/Services/Campaign/ExportService.php +++ b/app/Services/Campaign/ExportService.php @@ -315,6 +315,9 @@ protected function process(string $entity, $model): self /** @var EntityAsset $file */ foreach ($model->entity->files as $file) { + if (!isset($file->metadata['path'])) { + continue; + } $path = $file->metadata['path']; if (!Storage::exists($path)) { continue; diff --git a/app/Services/Campaign/GalleryService.php b/app/Services/Campaign/GalleryService.php index 02ef2d4b8..d60d47268 100644 --- a/app/Services/Campaign/GalleryService.php +++ b/app/Services/Campaign/GalleryService.php @@ -105,7 +105,6 @@ public function storageInfo(): array ]; } - /** * Total size in mb */ diff --git a/app/Services/Campaign/Import/ImportService.php b/app/Services/Campaign/Import/ImportService.php index be00879ce..fc0155744 100644 --- a/app/Services/Campaign/Import/ImportService.php +++ b/app/Services/Campaign/Import/ImportService.php @@ -4,6 +4,7 @@ use App\Enums\CampaignImportStatus; use App\Facades\CampaignCache; +use App\Facades\CharacterCache; use App\Models\CampaignImport; use App\Notifications\Header; use App\Services\Campaign\Import\Mappers\AbilityMapper; @@ -274,6 +275,7 @@ protected function moduleSettings(): self // Since modules and custom names are cached, any changes to them need to invalidate any existing cache CampaignCache::campaign($this->campaign)->clear(); + CharacterCache::campaign($this->campaign); return $this; } diff --git a/app/Services/Campaign/Import/Mappers/EntityMapper.php b/app/Services/Campaign/Import/Mappers/EntityMapper.php index 325a94617..9499459c2 100644 --- a/app/Services/Campaign/Import/Mappers/EntityMapper.php +++ b/app/Services/Campaign/Import/Mappers/EntityMapper.php @@ -154,12 +154,26 @@ protected function migrateToGallery(string $old): self return $this; } + $image = $this->migrateImage($img); + + if ($old == 'image_path') { + $this->entity->image_uuid = ImportIdMapper::getGallery($image->id); + } else { + $this->entity->header_uuid = ImportIdMapper::getGallery($image->id); + } + + return $this; + } + + protected function migrateImage(string $img): Image + { $imageExt = Str::after($img, '.'); //We need to create a new Image to migrate to the new system. $image = new Image(); $image->campaign_id = $this->campaign->id; $image->ext = $imageExt; + $image->created_by = $this->user->id; $image->name = $this->entity->name; $image->visibility_id = 1; $size = Storage::disk('local')->size($this->path . $img); @@ -170,13 +184,7 @@ protected function migrateToGallery(string $old): self Storage::writeStream($image->path, Storage::disk('local')->readStream($this->path . $img)); ImportIdMapper::putGallery($image->id, $image->id); - if ($old == 'image_path') { - $this->entity->image_uuid = ImportIdMapper::getGallery($image->id); - } else { - $this->entity->header_uuid = ImportIdMapper::getGallery($image->id); - } - - return $this; + return $image; } protected function gallery(): self @@ -213,7 +221,7 @@ protected function posts(): self foreach ($import as $field) { $post->$field = $data[$field]; } - if (!empty($data['location_id'])) { + if (!empty($data['location_id']) && ImportIdMapper::has('locations', $data['location_id'])) { $locationID = ImportIdMapper::get('locations', $data['location_id']); if (!empty($locationID)) { $post->location_id = $locationID; @@ -257,20 +265,23 @@ protected function assets(): self if (!empty($data['metadata'])) { if (!empty($data['metadata']['path'])) { $img = $data['metadata']['path']; - $ext = Str::afterLast($img, '.'); - $destination = 'w/' . $this->campaign->id . '/entity-assets/' . uniqid() . '.' . $ext; - if (!Storage::disk('local')->exists($this->path . $img)) { //dd('image ' . $this->path . $img . ' doesnt exist'); continue; } - Storage::writeStream($destination, Storage::disk('local')->readStream($this->path . $img)); - $data['metadata']['path'] = $destination; + + $image = $this->migrateImage($img); + $asset->image_uuid = $image->id; + unset($data['metadata']['path']); $asset->metadata = $data['metadata']; + } else { $asset->metadata = $data['metadata']; } } + if (isset($data['image_uuid'])) { + $asset->image_uuid = ImportIdMapper::getGallery($data['image_uuid']); + } $asset->created_by = $this->user->id; $asset->save(); } diff --git a/app/Services/Campaign/Import/Mappers/GalleryMapper.php b/app/Services/Campaign/Import/Mappers/GalleryMapper.php index ff4d8320d..d26454ae1 100644 --- a/app/Services/Campaign/Import/Mappers/GalleryMapper.php +++ b/app/Services/Campaign/Import/Mappers/GalleryMapper.php @@ -45,6 +45,8 @@ public function import(): void { $this->image = new Image(); $this->image->campaign_id = $this->campaign->id; + //Need to save to set the id otherwise it stores wrong data. + $this->image->save(); $this->mapping[$this->data['id']] = $this->image->id; ImportIdMapper::putGallery($this->data['id'], $this->image->id); diff --git a/app/Services/EntityFileService.php b/app/Services/EntityFileService.php index 39f44671e..3aa6891df 100644 --- a/app/Services/EntityFileService.php +++ b/app/Services/EntityFileService.php @@ -5,8 +5,12 @@ use App\Exceptions\EntityFileException; use App\Http\Requests\StoreEntityAsset; use App\Models\EntityAsset; +use App\Models\Image; +use App\Services\Campaign\GalleryService; use App\Traits\CampaignAware; use App\Traits\EntityAware; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Str; class EntityFileService { @@ -16,33 +20,59 @@ class EntityFileService /** * @throws EntityFileException */ - public function upload(StoreEntityAsset $request, string $field = 'file', string $folder = 'entities/files'): EntityAsset + public function upload(StoreEntityAsset $request, string $field = 'file'): EntityAsset { + /** @var GalleryService $service */ + $service = app()->make(GalleryService::class); + + // Prepare the file for the journey + $uploadedFile = $request->file($field); + // Already above max capacity? - if ($this->entity->files->count() >= $this->campaign->maxEntityFiles()) { + if ($this->entity->files->count() >= $this->campaign->maxEntityFiles() || $service->campaign($this->campaign)->available() < $uploadedFile->getSize() / 1024) { throw new EntityFileException('max'); } - // Prepare the file for the journey - $uploadedFile = $request->file($field); + if ($service->campaign($this->campaign)->available() < $uploadedFile->getSize() / 1024) { + throw new EntityFileException('max_size'); + } - $path = $request->file($field)->storePublicly($folder); $name = $request->get('name'); if (empty($name)) { $name = $uploadedFile->getClientOriginalName(); + $name = Str::beforeLast($name, '.'); } + $image = new Image(); + $image->campaign_id = $this->campaign->id; + $image->created_by = auth()->user()->id; + $image->ext = $uploadedFile->extension(); + $image->size = (int) ceil($uploadedFile->getSize() / 1024); // kb + $image->name = mb_substr($name, 0, 45); + $image->visibility_id = $this->campaign->defaultVisibilityID(); + $image->save(); + + $uploadedFile + ->storePubliclyAs( + $image->folder, + $image->file, + ['disk' => 's3'] + ); + $file = new EntityAsset(); $file->type_id = EntityAsset::TYPE_FILE; $file->entity_id = $this->entity->id; $file->metadata = [ - 'path' => $path, 'size' => $uploadedFile->getSize(), 'type' => $uploadedFile->getMimeType(), ]; $file->name = $name; $file->visibility_id = $request->get('visibility_id', 1); $file->is_pinned = $request->get('is_pinned', 1); + $file->image_uuid = $image->id; $file->save(); + + Cache::forget('campaign_' . $this->campaign->id . '_gallery'); + return $file; } } diff --git a/database/migrations/2024_07_26_160208_update_entity_assets_add_image_uuid.php b/database/migrations/2024_07_26_160208_update_entity_assets_add_image_uuid.php new file mode 100644 index 000000000..9e6319fed --- /dev/null +++ b/database/migrations/2024_07_26_160208_update_entity_assets_add_image_uuid.php @@ -0,0 +1,29 @@ +char('image_uuid', 36)->nullable(); + $table->foreign('image_uuid')->references('id')->on('images')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('entity_assets', function (Blueprint $table) { + $table->dropForeign('entity_assets_image_uuid_foreign'); + $table->dropColumn('image_uuid'); + }); + } +}; diff --git a/lang/en/crud.php b/lang/en/crud.php index a5a0c77db..32b69dbd8 100644 --- a/lang/en/crud.php +++ b/lang/en/crud.php @@ -170,8 +170,9 @@ 'manage' => 'Manage Entity Files', ], 'errors' => [ - 'max' => 'You have reached the maximum number (:max) of files for this entity.', - 'no_files' => 'No files.', + 'max' => 'You have reached the maximum number (:max) of files for this entity.', + 'max_size' => 'You have reached the maximum storage capacity for files of this campaign.', + 'no_files' => 'No files.', ], 'files' => 'Uploaded Files', 'hints' => [ diff --git a/resources/views/entities/components/assets.blade.php b/resources/views/entities/components/assets.blade.php index c6f774a64..a528cd3be 100644 --- a/resources/views/entities/components/assets.blade.php +++ b/resources/views/entities/components/assets.blade.php @@ -5,7 +5,7 @@ */ ?> @foreach ($model->entity->pinnedFiles as $asset) - + {{ $asset->name }} @endforeach diff --git a/resources/views/gallery/_image.blade.php b/resources/views/gallery/_image.blade.php index 43fc344aa..563adf56f 100644 --- a/resources/views/gallery/_image.blade.php +++ b/resources/views/gallery/_image.blade.php @@ -22,14 +22,14 @@ @else - @if ($image->isFont()) -
- -
- @else + @if ($image->hasThumbnail()) + @else +
+ +
@endif
@include('icons.visibility', ['icon' => $image->visibilityIcon()]) diff --git a/resources/views/gallery/file/_actions.blade.php b/resources/views/gallery/file/_actions.blade.php index 3743b17b3..be9dc2a70 100644 --- a/resources/views/gallery/file/_actions.blade.php +++ b/resources/views/gallery/file/_actions.blade.php @@ -1,6 +1,6 @@ @can('edit', [$image, $campaign]) - @if (!$image->isFont() && !$image->isFolder()) + @if ($image->hasThumbnail())
@else - @if ($image->isFont()) - - @else + @if ($image->hasThumbnail())
{{ $image->name }}
+ @else + @endif