diff --git a/app/Actions/Photos/ExportPhotosAction.php b/app/Actions/Photos/ExportPhotosAction.php new file mode 100644 index 00000000..e236c4ed --- /dev/null +++ b/app/Actions/Photos/ExportPhotosAction.php @@ -0,0 +1,27 @@ +photos() + ->filter($user->settings->photo_filters) + ->with(['photoItems' => fn (Builder $q) => $q + ->with('item:id,name') + ->with('tags:id,name'), + ]) + ->lazyById(); + + foreach ($photos as $photo) { + yield PhotoExport::fromModel($photo); + } + } +} diff --git a/app/Console/Commands/GenerateRandomPhotos.php b/app/Console/Commands/GenerateRandomPhotos.php index 3d146c18..2f692e30 100644 --- a/app/Console/Commands/GenerateRandomPhotos.php +++ b/app/Console/Commands/GenerateRandomPhotos.php @@ -16,7 +16,7 @@ public function handle(): void { /** @var User $user */ $user = User::query() - ->where('email', 'trashkiller@litterhero.com') + ->where('email', 'trashkiller@litterapp.com') ->first(); $bar = progress('Generating 1M photos with tags...', 1_000_000); @@ -34,6 +34,7 @@ public function handle(): void $photos[] = [ 'user_id' => $user->id, 'path' => 'photos/default.jpg', + 'original_file_name' => fake()->unique()->sentence().'default.jpg', 'created_at' => $now, 'updated_at' => $now, ]; diff --git a/app/DTO/PhotoExport.php b/app/DTO/PhotoExport.php new file mode 100644 index 00000000..52c6b312 --- /dev/null +++ b/app/DTO/PhotoExport.php @@ -0,0 +1,46 @@ +> $items + */ + public function __construct( + public int $id, + public string $original_file_name, + public ?float $latitude, + public ?float $longitude, + public ?string $taken_at_local, + public string $created_at, + public Collection $items, + ) { + } + + public static function fromModel(Photo $photo): static + { + return new static( + id: $photo->id, + original_file_name: $photo->original_file_name, + latitude: $photo->latitude, + longitude: $photo->longitude, + taken_at_local: $photo->taken_at_local, + created_at: $photo->created_at?->toIso8601String(), + items: $photo->photoItems->map(fn (PhotoItem $photoItem): array => [ + 'name' => $photoItem->item?->name, + 'picked_up' => $photoItem->picked_up, + 'recycled' => $photoItem->recycled, + 'deposit' => $photoItem->deposit, + 'quantity' => $photoItem->quantity, + 'tags' => $photoItem->tags->pluck('name')->toArray(), + ]), + ); + } +} diff --git a/app/Http/Controllers/Photos/ExportPhotosController.php b/app/Http/Controllers/Photos/ExportPhotosController.php new file mode 100644 index 00000000..b2b712d2 --- /dev/null +++ b/app/Http/Controllers/Photos/ExportPhotosController.php @@ -0,0 +1,24 @@ +user(); + + $photos = $action->run($user); + + return response()->streamJson(['photos' => $photos], 200, [ + 'Content-Type' => 'application/json', + 'Content-Disposition' => 'attachment; filename="photos.json"', + ]); + } +} diff --git a/app/Models/PhotoItem.php b/app/Models/PhotoItem.php index 6c8906da..b6ed0fef 100644 --- a/app/Models/PhotoItem.php +++ b/app/Models/PhotoItem.php @@ -10,7 +10,7 @@ /** * @property Collection $tags - * @property Photo $photo + * @property-read Photo $photo */ class PhotoItem extends Pivot { diff --git a/database/factories/PhotoItemFactory.php b/database/factories/PhotoItemFactory.php index d696f2c4..626d2330 100644 --- a/database/factories/PhotoItemFactory.php +++ b/database/factories/PhotoItemFactory.php @@ -2,6 +2,8 @@ namespace Database\Factories; +use App\Models\Item; +use App\Models\Photo; use App\Models\PhotoItem; use Illuminate\Database\Eloquent\Factories\Factory; @@ -18,7 +20,8 @@ class PhotoItemFactory extends Factory public function definition(): array { return [ - // + 'photo_id' => Photo::factory(), + 'item_id' => Item::factory(), ]; } } diff --git a/resources/js/Pages/Photos/Index.vue b/resources/js/Pages/Photos/Index.vue index 725d6d8e..087ff7bb 100644 --- a/resources/js/Pages/Photos/Index.vue +++ b/resources/js/Pages/Photos/Index.vue @@ -156,6 +156,10 @@ const filter = (filters) => { clearSelection(); router.get(window.location.pathname, filters); } + +const exportData = () => { + window.location.href = route('photos.export'); +}