diff --git a/README.md b/README.md index e4662bf..4cb087b 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,40 @@ class DatabaseSeeder extends OzuSeeder } ``` +### Production seeder + +To ease the first deployment of your project, you can use the `OzuProductionSeeder` class to seed ozu with some production data: + +```php +use Code16\OzuClient\Support\Database\OzuProductionSeeder; +// ... + +class DatabaseSeeder extends OzuProductionSeeder +{ + public function run(): void + { + // At this point, you'll have to create your real data, you're not forced to save + // it in your local database, since Ozu will accept a model without an ID, and seed it in Production. + $myRealProjects = Project::factory() + ->count(12) + ->has(Media::factory()->image('cover')->withFile(), 'cover') + ->has(Media::factory()->image('visuals')->withFile()->count(3), 'visuals') + ->sequence(fn ($sequence) => [ + 'order' => $sequence->index + 1, + 'country' => fake()->country(), + ]) + ->make(); + + $myRealProjects + ->each(fn($project) => $this->createInOzu($project) + ->withFile('cover', $project->cover->file_name) + ->withFileList('visuals', $project->visuals->pluck('file_name')->toArray()) + ); + // ... + } +} +``` + ### Check the demo project for an example You can refer to the Ozu demo project [dvlpp/ozu-demo](https://github.com/dvlpp/ozu-demo) for an example of a simple project that uses Ozu. diff --git a/src/Client.php b/src/Client.php index db8f151..85d446e 100644 --- a/src/Client.php +++ b/src/Client.php @@ -22,6 +22,26 @@ public function updateCollectionSharpConfiguration(string $collectionKey, array ); } + public function seed(string $collection, array $payload): mixed + { + return $this->http()->post( + sprintf('/collections/%s/seed', $collection), + $payload + )->json(); + } + + public function seedFile(string $collection, int $id, string $field, string $path): mixed + { + return $this->http() + ->attach('file', file_get_contents($path), basename($path)) + ->post( + sprintf('/collections/%s/seed/%s/file', $collection, $id), + [ + 'field' => $field, + ] + )->getBody()?->getContents(); + } + public function apiKey(): ?string { return $this->apiKey; diff --git a/src/Deploy/Crawler/Observer.php b/src/Deploy/Crawler/Observer.php new file mode 100644 index 0000000..e69de29 diff --git a/src/Deploy/DeployServiceProvider.php b/src/Deploy/DeployServiceProvider.php new file mode 100644 index 0000000..e69de29 diff --git a/src/Deploy/Jobs/CrawlSite.php b/src/Deploy/Jobs/CrawlSite.php new file mode 100644 index 0000000..e69de29 diff --git a/src/Deploy/Jobs/CrawlSiteHandler.php b/src/Deploy/Jobs/CrawlSiteHandler.php new file mode 100644 index 0000000..e69de29 diff --git a/src/Deploy/Routing/UrlGenerator.php b/src/Deploy/Routing/UrlGenerator.php new file mode 100644 index 0000000..e69de29 diff --git a/src/Deploy/RoutingServiceProvider.php b/src/Deploy/RoutingServiceProvider.php new file mode 100644 index 0000000..e69de29 diff --git a/src/Eloquent/Media.php b/src/Eloquent/Media.php index 59a7c0b..29b55c4 100644 --- a/src/Eloquent/Media.php +++ b/src/Eloquent/Media.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Support\Facades\Schema; +use Number; class Media extends Model { @@ -52,15 +53,9 @@ public function humanReadableSize($precision = 2): ?string return null; } - if ($this->size >= 0) { - $size = (int) $this->size; - $base = log($size) / log(1024); - $suffixes = [' bytes', ' KB', ' MB', ' GB', ' TB']; + $size = (int) $this->size; - return $this->size === 0 ? '0 bytes' : (round(pow(1024, $base - floor($base)), $precision).$suffixes[floor($base)]); - } else { - return $this->size; - } + return Number::fileSize($size, 1, 3); } /** diff --git a/src/Support/Database/OzuProductionSeeder.php b/src/Support/Database/OzuProductionSeeder.php new file mode 100644 index 0000000..bc09ab9 --- /dev/null +++ b/src/Support/Database/OzuProductionSeeder.php @@ -0,0 +1,72 @@ +client = app(Client::class); + } + + protected function createInOzu(Model $item): static + { + if (! in_array(IsOzuModel::class, class_uses_recursive($item))) { + throw new \InvalidArgumentException($item::class." doesn't have the IsOzuModel trait"); + } + + $this->currentCollectionKey = $collectionKey = $item?->ozuCollectionKey(); + + if (! $collectionKey) { + throw new \InvalidArgumentException('Unable to retrieve collection key.'); + } + + $this->createdId = $this->client->seed($collectionKey, $item->toArray())['id'] ?? null; + + return $this; + } + + protected function withFile(string $field, string $path, ?int $forceId = null): static + { + if (! $forceId && ! $this->createdId) { + throw new \InvalidArgumentException('No item created yet. Try calling createInOzu() first.'); + } + + if (! File::exists($path)) { + throw new \InvalidArgumentException("File not found at path: {$path}"); + } + + $this->client->seedFile($this->currentCollectionKey, $forceId ?? $this->createdId, $field, $path); + + return $this; + } + + /** + * @param array $paths + */ + protected function withFileList(string $field, array $paths, ?int $forceId = null): static + { + foreach ($paths as $path) { + $this->withFile($field, $path, $forceId); + } + + return $this; + } + + protected function id(): ?int + { + return $this->createdId; + } +} diff --git a/tests/ArchTest.php b/tests/ArchTest.php index c879a5b..fc32832 100644 --- a/tests/ArchTest.php +++ b/tests/ArchTest.php @@ -1,5 +1,5 @@ expect(['die', 'dd', 'dump', 'ray', 'ddRawSql', 'var_dump']) + ->expect(['die', 'dd', 'dump', 'ray', 'ds', 'ddRawSql', 'var_dump']) ->each->not->toBeUsed(); diff --git a/tests/Fixtures/DummyTestModel.php b/tests/Fixtures/DummyTestModel.php index 825559a..01f1fac 100644 --- a/tests/Fixtures/DummyTestModel.php +++ b/tests/Fixtures/DummyTestModel.php @@ -14,6 +14,8 @@ class DummyTestModel extends Model use IsOzuModel; + protected $guarded = []; + public static function configureOzuCollection(OzuCollectionConfig $config): OzuCollectionConfig { return $config; diff --git a/tests/Unit/Database/OzuProductionSeederTest.php b/tests/Unit/Database/OzuProductionSeederTest.php new file mode 100644 index 0000000..797fc9c --- /dev/null +++ b/tests/Unit/Database/OzuProductionSeederTest.php @@ -0,0 +1,61 @@ +set('ozu-client.api_host', 'http://ozu.test'); + config()->set('ozu-client.api_key', 'api_key'); + config()->set('ozu-client.api_version', 'v1'); + config()->set('ozu-client.website_key', 'key'); + + $seeder = new class extends OzuProductionSeeder + { + public function run() + { + $this->createInOzu(DummyTestModel::make([ + 'title' => 'Project 1', + ]))->id(); + } + }; + + $seeder->run(); + Http::assertSent(function (Illuminate\Http\Client\Request $request) { + return + $request->url() === (sprintf('http://ozu.test/api/v1/key/collections/%s/seed', app(DummyTestModel::class)->ozuCollectionKey())) + && collect($request->data())->has('title') + && $request->data()['title'] === 'Project 1'; + }); +}); + +it('allows users to seed images on models in production', function () { + Http::fake(); + Storage::fake('local'); + + config()->set('ozu-client.api_host', 'http://ozu.test'); + config()->set('ozu-client.api_key', 'api_key'); + config()->set('ozu-client.api_version', 'v1'); + config()->set('ozu-client.website_key', 'key'); + + $seeder = new class extends OzuProductionSeeder + { + public function run() + { + $path = Storage::disk('local')->path('/images/image.jpg'); + UploadedFile::fake()->image('image.jpg')->storeAs('/images', 'image.jpg', ['disk' => 'local']); + + $this->createInOzu(DummyTestModel::make([ + 'title' => 'Project 1', + ]))->withFile('cover', $path, forceId: 5); + } + }; + + $seeder->run(); + Http::assertSent(function (Illuminate\Http\Client\Request $request) { + return + $request->url() === (sprintf('http://ozu.test/api/v1/key/collections/%s/seed/5/file', app(DummyTestModel::class)->ozuCollectionKey())) + && collect($request->data())->keyBy('name')->has(['file', 'field']); + }); +});