diff --git a/CHANGELOG.md b/CHANGELOG.md index 604fa93..f21d03b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ # Changelog -All notable changes to `Jocko Client` will be documented in this file. +All notable changes to `Ozu Client` will be documented in this file. diff --git a/README.md b/README.md index b9c176b..b666e83 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# Jocko Client +# ozu Client -[![Latest Version on Packagist](https://img.shields.io/packagist/v/code16/jocko-client.svg?style=flat-square)](https://packagist.org/packages/code16/jocko-client) -[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/code16/jocko-client/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/code16/jocko-client/actions?query=workflow%3Arun-tests+branch%3Amain) -[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/code16/jocko-client/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/code16/jocko-client/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) -[![Total Downloads](https://img.shields.io/packagist/dt/code16/jocko-client.svg?style=flat-square)](https://packagist.org/packages/code16/jocko-client) +[![Latest Version on Packagist](https://img.shields.io/packagist/v/code16/ozu-client.svg?style=flat-square)](https://packagist.org/packages/code16/ozu-client) +[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/code16/ozu-client/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/code16/ozu-client/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/code16/ozu-client/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/code16/ozu-client/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/code16/ozu-client.svg?style=flat-square)](https://packagist.org/packages/code16/ozu-client) This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. ## Support us -[](https://spatie.be/github-ad-click/Jocko Client) +[](https://spatie.be/github-ad-click/ozu Client) We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). @@ -20,13 +20,13 @@ We highly appreciate you sending us a postcard from your hometown, mentioning wh You can install the package via composer: ```bash -composer require code16/jocko-client +composer require code16/ozu-client ``` You can publish the config file with: ```bash -php artisan vendor:publish --tag="jocko-client-config" +php artisan vendor:publish --tag="ozu-client-config" ``` This is the contents of the published config file: diff --git a/composer.json b/composer.json index 9e9cb6a..3d4a953 100644 --- a/composer.json +++ b/composer.json @@ -1,12 +1,12 @@ { - "name": "code16/jocko-client", - "description": "Client to access to Jocko API (https://github.com/code16/jocko)", + "name": "code16/ozu-client", + "description": "Client to access to Ozu API (https://github.com/code16/jocko)", "keywords": [ "code16", "laravel", - "jocko-client" + "ozu-client" ], - "homepage": "https://github.com/code16/jocko-client", + "homepage": "https://github.com/code16/ozu-client", "license": "MIT", "authors": [ { @@ -16,17 +16,17 @@ } ], "require": { - "php": "^8.1", - "calebporzio/sushi": "^2.5", + "php": "^8.2", "code16/laravel-content-renderer": "^1.1.0", - "illuminate/contracts": "^10.0", - "spatie/laravel-export": "^1.1.1", - "spatie/laravel-package-tools": "^1.14.0" + "illuminate/contracts": "^11.0", + "intervention/image-laravel": "^1.0", + "spatie/laravel-package-tools": "^1.14.0", + "spatie/laravel-sluggable": "^3.6" }, "require-dev": { "laravel/pint": "^1.0", - "nunomaduro/collision": "^7.9", - "orchestra/testbench": "^8.0", + "nunomaduro/collision": "^8.0", + "orchestra/testbench": "^9.0", "pestphp/pest": "^2.0", "pestphp/pest-plugin-arch": "^2.0", "pestphp/pest-plugin-laravel": "^2.0", @@ -34,13 +34,13 @@ }, "autoload": { "psr-4": { - "Code16\\JockoClient\\": "src", - "Code16\\JockoClient\\Database\\Factories\\": "database/factories" + "Code16\\OzuClient\\": "src", + "Code16\\OzuClient\\Database\\Factories\\": "database/factories" } }, "autoload-dev": { "psr-4": { - "Code16\\JockoClient\\Tests\\": "tests" + "Code16\\OzuClient\\Tests\\": "tests" } }, "scripts": { @@ -60,10 +60,10 @@ "extra": { "laravel": { "providers": [ - "Code16\\JockoClient\\JockoServiceProvider" + "Code16\\OzuClient\\OzuServiceProvider" ], "aliases": { - "Jocko": "Code16\\JockoClient\\Facades\\Jocko" + "Ozu": "Code16\\OzuClient\\Facades\\Ozu" } } }, diff --git a/config/jocko-client.php b/config/jocko-client.php deleted file mode 100644 index 74243b8..0000000 --- a/config/jocko-client.php +++ /dev/null @@ -1,10 +0,0 @@ - env('JOCKO_API_HOST', 'http://jocko.test/'), - 'api_key' => env('JOCKO_API_KEY'), - 'website_key' => env('JOCKO_WEBSITE_KEY'), - 'should_cache' => env('JOCKO_SHOULD_CACHE', true), - 'preview' => env('JOCKO_PREVIEW', false), -]; diff --git a/config/ozu-client.php b/config/ozu-client.php new file mode 100644 index 0000000..d70fbbb --- /dev/null +++ b/config/ozu-client.php @@ -0,0 +1,11 @@ + env('OZU_API_HOST', 'https://ozu.code16.fr/'), + 'api_key' => env('OZU_API_KEY'), + 'api_version' => env('OZU_API_VERSION', 'v1'), + 'cdn_url' => env('OZU_CDN_URL'), + 'website_key' => env('OZU_WEBSITE_KEY'), + 'collections' => [], +]; diff --git a/database/factories/MediaFactory.php b/database/factories/MediaFactory.php new file mode 100644 index 0000000..b18130d --- /dev/null +++ b/database/factories/MediaFactory.php @@ -0,0 +1,57 @@ +state(function (array $attributes) use ($key) { + return [ + 'model_key' => $key, + 'file_name' => sprintf('data/medias/%s.jpg', $this->faker->unique()->slug()), + 'mime_type' => 'image/jpeg', + 'disk' => 'local', + 'size' => $this->faker->numberBetween(100, 100000), + ]; + }); + } + + public function withFile(?string $fileName = null) + { + return $this->state(function (array $attributes) use ($fileName) { + $fileName = $fileName ?: fake()->slug() . '.jpg'; + $path = $this->getRandomFixtureImagePath(); + + Storage::disk('local') + ->put("/data/medias/$fileName", file_get_contents($path)); + + return [ + 'file_name' => "data/medias/$fileName", + ]; + }); + } + + private function getRandomFixtureImagePath(): string + { + return base_path( + sprintf( + 'vendor/code16/ozu-client/database/fixtures/images/%s.jpeg', + rand(1, 26) + ) + ); + } +} diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php deleted file mode 100644 index 635b4ea..0000000 --- a/database/factories/ModelFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -id(); - - // add fields - - $table->timestamps(); - }); - } -}; diff --git a/database/migrations/create_ozu_tables.php b/database/migrations/create_ozu_tables.php new file mode 100644 index 0000000..3845946 --- /dev/null +++ b/database/migrations/create_ozu_tables.php @@ -0,0 +1,24 @@ +id(); + $table->morphs('model'); + $table->string('model_key')->nullable(); + $table->string('file_name')->nullable(); + $table->string('mime_type')->nullable(); + $table->string('disk')->default('local')->nullable(); + $table->unsignedInteger('size')->nullable(); + $table->text('custom_properties')->nullable(); + $table->unsignedInteger('order')->nullable(); + $table->timestamps(); + }); + } +}; diff --git a/resources/views/components/file.blade.php b/resources/views/components/file.blade.php index b37dbde..5a5fce5 100644 --- a/resources/views/components/file.blade.php +++ b/resources/views/components/file.blade.php @@ -1,6 +1,6 @@ @php /** - * @see \Code16\JockoClient\View\Components\Image + * @see \Code16\OzuClient\View\Components\Image */ @endphp diff --git a/resources/views/components/image.blade.php b/resources/views/components/image.blade.php index dcebb81..baa610f 100644 --- a/resources/views/components/image.blade.php +++ b/resources/views/components/image.blade.php @@ -1,6 +1,6 @@ @php /** - * @see \Code16\JockoClient\View\Components\Image + * @see \Code16\OzuClient\View\Components\Image */ @endphp diff --git a/resources/views/components/preview-alert.blade.php b/resources/views/components/preview-alert.blade.php index d8bbdad..c891930 100644 --- a/resources/views/components/preview-alert.blade.php +++ b/resources/views/components/preview-alert.blade.php @@ -1,9 +1,9 @@ -@if(\Code16\JockoClient\Facades\Jocko::isPreview()) -
- Prévisualisation du site. Pour appliquer les changements, rendez-vous dans la - - page publication - . -
-@endif +{{--@if(\Code16\OzuClient\Facades\Ozu::isPreview())--}} +{{--
--}} +{{-- Prévisualisation du site. Pour appliquer les changements, rendez-vous dans la--}} +{{-- --}} +{{-- page publication--}} +{{-- .--}} +{{--
--}} +{{--@endif--}} diff --git a/resources/views/preview-unauthorized.blade.php b/resources/views/preview-unauthorized.blade.php index 30b36b2..4857726 100644 --- a/resources/views/preview-unauthorized.blade.php +++ b/resources/views/preview-unauthorized.blade.php @@ -15,7 +15,7 @@
- Le lien de prévisualisation a expiré, veuillez l’ouvrir de nouveau depuis le menu de votre tableau de bord. + Le lien de prévisualisation a expiré, veuillez l’ouvrir de nouveau depuis le menu de votre tableau de bord.
diff --git a/routes/web.php b/routes/web.php deleted file mode 100644 index d589fdc..0000000 --- a/routes/web.php +++ /dev/null @@ -1,14 +0,0 @@ -group(function() { - Route::get('/preview', [PreviewController::class, 'show']) - ->withoutMiddleware(PreviewAuthenticate::class) - ->name('jocko.preview.show'); - }); - diff --git a/src/Client.php b/src/Client.php old mode 100755 new mode 100644 index 1e64921..5dea9c4 --- a/src/Client.php +++ b/src/Client.php @@ -1,10 +1,8 @@ withCache($collectionKey, fn () => - $this->http() - ->get($this->url("/collections/$collectionKey")) - ->json() - )['data']; - } - - public function getCollectionMeta(string $collectionKey): array - { - return $this->withCache($collectionKey, fn () => - $this->http() - ->get($this->url("/collections/$collectionKey")) - ->json() - )['meta']; - } - - public function getSettings(): array - { - return $this->withCache('settings', fn () => - $this->http() - ->get($this->url('/settings')) - ->json('data') + $this->http()->post( + sprintf('/collections/%s/configure', $collectionKey), + $collectionData ); } - public function searchUrl(string $collectionKey): string - { - return $this->url("/collections/$collectionKey/search"); - } - - public function withCache(string $key, Closure $callback) - { - return Cache::driver($this->shouldCache() ? 'file' : 'array') - ->rememberForever("jocko:$key", $callback); - } - - /** - * env: JOCKO_SHOULD_CACHE - */ - public function shouldCache(): bool - { - if($this->isPreview()) { - return false; - } - - return $this->shouldCache || $this->isExporting(); - } - - public function isExporting(): bool - { - return request()->hasHeader('X-Laravel-Export'); - } - - public function isPreview(): bool - { - return $this->isPreview && !$this->isExporting(); - } - public function apiKey(): ?string { return $this->apiKey; } - protected function url(string $endpoint = ''): string - { - $host = rtrim($this->apiHost, '/'); - $websiteKey = $this->websiteKey; - $endpoint = ltrim($endpoint, '/'); - - return "$host/api/v2/$websiteKey/$endpoint"; - } - protected function http(): PendingRequest { return Http::withToken($this->apiKey) + ->baseUrl( + sprintf( + '%s/api/%s/%s', + rtrim($this->apiHost, '/'), + $this->apiVersion, + $this->websiteKey, + ) + ) ->acceptJson() ->throw(); } diff --git a/src/Console/ConfigureCmsCommand.php b/src/Console/ConfigureCmsCommand.php new file mode 100644 index 0000000..c13151b --- /dev/null +++ b/src/Console/ConfigureCmsCommand.php @@ -0,0 +1,82 @@ +info('No collections to configure.'); + return; + } + + collect(config('ozu-client.collections')) + ->map(function ($collectionClassName, $k) { + $model = new $collectionClassName; + $collection = $collectionClassName::configureOzuCollection(new OzuCollectionConfig()); + $list = $collectionClassName::configureOzuCollectionList(new OzuCollectionListConfig()); + $form = $collectionClassName::configureOzuCollectionForm(new OzuCollectionFormConfig()); + + return [ + 'key' => $model->ozuCollectionKey(), + 'label' => $collection->label(), + 'icon' => $collection->icon(), + 'hasPublicationState' => $collection->hasPublicationState(), + 'isCreatable' => $collection->isCreatable(), + 'isDeletable' => $collection->isDeletable(), + 'order' => $k+1, + 'list' => [ + 'isReorderable' => $list->isReorderable(), + 'isSearchable' => $list->isSearchable(), + 'isPaginated' => $list->isPaginated(), + 'columns' => $list + ->columns() + ->map(fn (OzuColumn $column) => [ + 'type' => $column->type(), + 'key' => $column->key(), + 'label' => $column->label(), + 'size' => $column->size(), + ]) + ], + 'form' => [ + 'fields' => $form + ->customFields() + ->map(fn (OzuField $field) => $field->toArray()) + ], + 'customFields' => collect(Schema::getColumnListing($model->getTable())) + ->filter(fn (string $column) => !in_array($column, $model::$ozuColumns)) + ->mapWithKeys(fn (string $column) => [ + $column => match(Schema::getColumnType($model->getTable(), $column)) { + 'datetime', 'timestamps' => 'dateTime', + 'date' => 'date', + 'int', 'bigint', 'smallint', 'mediumint', 'tinyint' => 'integer', + 'float', 'double' => 'float', + default => 'string', + } + ]) + ]; + }) + ->each(function (array $collection) { + $this->info('Update CMS configuration for [' . $collection['key'] . '].'); + Ozu::updateCollectionSharpConfiguration( + $collection['key'], + $collection + ); + }); + + $this->info('CMS configuration sent to Ozu.'); + } +} diff --git a/src/Deploy/Crawler/Observer.php b/src/Deploy/Crawler/Observer.php index 4ce2ed8..fa23d69 100644 --- a/src/Deploy/Crawler/Observer.php +++ b/src/Deploy/Crawler/Observer.php @@ -1,6 +1,6 @@ set('app.asset_url', '/'); + $this->app[Dispatcher::class]->map([ \Spatie\Export\Jobs\CrawlSite::class => CrawlSiteHandler::class, ]); diff --git a/src/Deploy/Jobs/CrawlSite.php b/src/Deploy/Jobs/CrawlSite.php index a0369af..a51e422 100644 --- a/src/Deploy/Jobs/CrawlSite.php +++ b/src/Deploy/Jobs/CrawlSite.php @@ -1,7 +1,7 @@ map(fn ($attributes) => [ - ...collect($attributes) - ->mapWithKeys(fn ($value, $key) => [ - $key => is_array($value) ? json_encode($value) : $value - ]) - ]) - ->toArray(); - } -} diff --git a/src/Eloquent/Concerns/HasCollectionGlobalScopes.php b/src/Eloquent/Concerns/HasCollectionGlobalScopes.php deleted file mode 100644 index b13db14..0000000 --- a/src/Eloquent/Concerns/HasCollectionGlobalScopes.php +++ /dev/null @@ -1,24 +0,0 @@ -jockoCollectionKey()); - - if($meta['reorderable']) { - $query->orderBy('order'); - } - }); - } -} diff --git a/src/Eloquent/Concerns/ManagesSushiCache.php b/src/Eloquent/Concerns/ManagesSushiCache.php deleted file mode 100644 index 90c5d15..0000000 --- a/src/Eloquent/Concerns/ManagesSushiCache.php +++ /dev/null @@ -1,45 +0,0 @@ -clearSushiCache(); - } - } - - public function clearSushiCache(): void - { - $files = glob($this->sushiCacheDirectory().'/'.config('sushi.cache-prefix', 'sushi').'-*.sqlite'); - - foreach ($files as $filename) { - @unlink($filename); - } - } - - /** - * @see Sushi::sushiCacheDirectory - */ - protected function sushiCacheDirectory(): string - { - return realpath(storage_path('framework/cache')); - } - - /** - * @see Sushi::sushiShouldCache - */ - protected function sushiShouldCache(): bool - { - return Jocko::shouldCache(); - } -} diff --git a/src/Eloquent/Concerns/ManagesSushiConnections.php b/src/Eloquent/Concerns/ManagesSushiConnections.php deleted file mode 100644 index 7f1adc3..0000000 --- a/src/Eloquent/Concerns/ManagesSushiConnections.php +++ /dev/null @@ -1,34 +0,0 @@ -morphOne(Media::class, 'model') + ->where('model_key', 'cover'); + } + + public function getSlugOptions(): SlugOptions + { + return SlugOptions::create() + ->generateSlugsFrom('title') + ->saveSlugsTo('slug'); + } + + public function ozuCollectionKey(): string + { + return $this->getTable(); + } + + abstract public static function configureOzuCollection(OzuCollectionConfig $config): OzuCollectionConfig; + + abstract public static function configureOzuCollectionList(OzuCollectionListConfig $config): OzuCollectionListConfig; + + abstract public static function configureOzuCollectionForm(OzuCollectionFormConfig $config): OzuCollectionFormConfig; +} diff --git a/src/Eloquent/JockoModel.php b/src/Eloquent/JockoModel.php deleted file mode 100644 index 7799abd..0000000 --- a/src/Eloquent/JockoModel.php +++ /dev/null @@ -1,42 +0,0 @@ -castCollection(Jocko::getCollection($this->jockoCollectionKey())); - } - - public function jockoCollectionKey(): string - { - return str(class_basename(get_class($this))) - ->snake() - ->plural(); - } -} diff --git a/src/Eloquent/Media.php b/src/Eloquent/Media.php new file mode 100644 index 0000000..370cd5c --- /dev/null +++ b/src/Eloquent/Media.php @@ -0,0 +1,35 @@ +morphTo('model'); + } + + public function thumbnail(int $width = null, int $height = null, bool $fit = false): ?string + { + return app(Thumbnail::class) + ->forMedia($this) + ->make($width, $height, $fit); + } +} diff --git a/src/Facades/Jocko.php b/src/Facades/Ozu.php similarity index 53% rename from src/Facades/Jocko.php rename to src/Facades/Ozu.php index 126b8a1..4861ac3 100644 --- a/src/Facades/Jocko.php +++ b/src/Facades/Ozu.php @@ -1,14 +1,14 @@ has('jocko_preview_auth')) { - return redirect()->to('/'); - } - - if(Hash::check(config('jocko-client.api_key').date('Y-m-d'), request()->get('token'))) { - session()->put('jocko_preview_auth', true); - return redirect()->to('/'); - } - - return response()->view('jocko::preview-unauthorized', [], 401); - } -} diff --git a/src/Http/Middleware/PreviewAuthenticate.php b/src/Http/Middleware/PreviewAuthenticate.php deleted file mode 100644 index 05f69a8..0000000 --- a/src/Http/Middleware/PreviewAuthenticate.php +++ /dev/null @@ -1,26 +0,0 @@ -authenticate($request, guards: ['jocko-preview']); - - return $next($request); - } - - protected function redirectTo($request): ?string - { - return route('jocko.preview.show'); - } -} diff --git a/src/JockoServiceProvider.php b/src/JockoServiceProvider.php deleted file mode 100644 index 39d3172..0000000 --- a/src/JockoServiceProvider.php +++ /dev/null @@ -1,81 +0,0 @@ -name('jocko-client') - ->hasRoute('web') - ->hasConfigFile(); - } - - public function register() - { - parent::register(); - - $this->app->singleton(Client::class, function () { - return new Client( - apiHost: config('jocko-client.api_host'), - apiKey: config('jocko-client.api_key'), - websiteKey: config('jocko-client.website_key'), - shouldCache: config('jocko-client.should_cache'), - isPreview: config('jocko-client.preview'), - ); - }); - - $this->app->bind(Paginator::class, StaticPaginator::class); - $this->app->bind(LengthAwarePaginator::class, StaticLengthAwarePaginator::class); - - $this->app->register(DeployServiceProvider::class); - } - - public function boot() - { - parent::boot(); - - if(config('jocko-client.preview')) { - config()->set('auth.guards.jocko-preview', [ - 'driver' => 'jocko-preview', - ]); - - $this->app['auth']->extend('jocko-preview', function ($app, $name, array $config) { - return new PreviewGuard($app['session.store']); - }); - - $this->app[Kernel::class]->appendMiddlewareToGroup('web', PreviewAuthenticate::class); - } - - $this->loadViewsFrom(__DIR__.'/../resources/views', 'jocko'); - - $this->publishes([ - __DIR__.'/../resources/views/components/file.blade.php' => resource_path('views/vendor/jocko/components/file.blade.php'), - __DIR__.'/../resources/views/components/image.blade.php' => resource_path('views/vendor/jocko/components/image.blade.php'), - ], 'jocko-views'); - - Blade::componentNamespace('Code16\\JockoClient\\View\\Components\\Content', 'jocko-content'); - Blade::component(Content::class, 'jocko-content'); - Blade::component(Image::class, 'jocko-image'); - Blade::component(File::class, 'jocko-file'); - } -} diff --git a/src/OzuCms/Form/OzuCheckField.php b/src/OzuCms/Form/OzuCheckField.php new file mode 100644 index 0000000..bae1a63 --- /dev/null +++ b/src/OzuCms/Form/OzuCheckField.php @@ -0,0 +1,25 @@ + $this->text, + ]); + } +} diff --git a/src/OzuCms/Form/OzuDateField.php b/src/OzuCms/Form/OzuDateField.php new file mode 100644 index 0000000..239c816 --- /dev/null +++ b/src/OzuCms/Form/OzuDateField.php @@ -0,0 +1,27 @@ +hasTime = $hasTime; + + return $this; + } + + public function type(): string + { + return 'date'; + } + + public function toArray(): array + { + return array_merge(parent::toArray(), [ + 'hasTime' => $this->hasTime, + ]); + } +} diff --git a/src/OzuCms/Form/OzuEditorField.php b/src/OzuCms/Form/OzuEditorField.php new file mode 100644 index 0000000..b56ce55 --- /dev/null +++ b/src/OzuCms/Form/OzuEditorField.php @@ -0,0 +1,59 @@ +withoutParagraphs = true; + + return $this; + } + + public function setToolbar(array $toolbar): self + { + $this->toolbar = $toolbar; + + return $this; + } + + public function hideToolbar(): self + { + $this->hideToolbar = true; + + return $this; + } + + public function setHeight(int $height, int|null $maxHeight = null): self + { + $this->height = $height; + $this->maxHeight = $maxHeight; + + return $this; + } + + public function type(): string + { + return 'editor'; + } + + public function toArray(): array + { + return array_merge(parent::toArray(), [ + 'withoutParagraphs' => $this->withoutParagraphs, + 'hideToolbar' => $this->hideToolbar, + 'toolbar' => $this->toolbar, + 'height' => $this->height, + 'maxHeight' => $this->maxHeight, + ]); + } +} diff --git a/src/OzuCms/Form/OzuField.php b/src/OzuCms/Form/OzuField.php new file mode 100644 index 0000000..66ff6b8 --- /dev/null +++ b/src/OzuCms/Form/OzuField.php @@ -0,0 +1,97 @@ +label = $label; + + return $this; + } + + public function setHelpMessage(string $helpMessage) + { + $this->helpMessage = $helpMessage; + + return $this; + } + + public function setValidationRules(array $rules): self + { + $this->validationRules = $rules; + + return $this; + } + + public function setIsUpdatable(bool $isUpdatable = true): self + { + $this->isUpdatable = $isUpdatable; + + return $this; + } + + abstract public function type(): string; + + public function toArray(): array + { + return [ + 'type' => $this->type(), + 'key' => $this->key, + 'label' => $this->label, + 'validationRules' => $this->validationRules, + 'helpMessage' => $this->helpMessage, + 'isUpdatable' => $this->isUpdatable, + ]; + } +} diff --git a/src/OzuCms/Form/OzuFileListField.php b/src/OzuCms/Form/OzuFileListField.php new file mode 100644 index 0000000..b0bdb8f --- /dev/null +++ b/src/OzuCms/Form/OzuFileListField.php @@ -0,0 +1,45 @@ +maxItems = $maxItems; + + return $this; + } + + public function setHasLegend(bool $hasLegend = true): self + { + $this->hasLegend = $hasLegend; + + return $this; + } + + public function setMaxFileSize(int $maxFileSizeInMB): self + { + $this->maxFileSizeInMB = $maxFileSizeInMB; + + return $this; + } + + public function type(): string + { + return 'fileList'; + } + + public function toArray(): array + { + return array_merge(parent::toArray(), [ + 'maxItems' => $this->maxItems, + 'hasLegend' => $this->hasLegend, + 'maxFileSize' => $this->maxFileSizeInMB, + ]); + } +} diff --git a/src/OzuCms/Form/OzuImageField.php b/src/OzuCms/Form/OzuImageField.php new file mode 100644 index 0000000..98e85a5 --- /dev/null +++ b/src/OzuCms/Form/OzuImageField.php @@ -0,0 +1,45 @@ +hasLegend = $hasLegend; + + return $this; + } + + public function setFileFiler(string|array|null $fileFilter): self + { + $this->fileFilter = $fileFilter; + + return $this; + } + + public function setMaxFileSizeInMB(int $maxFileSizeInMB): self + { + $this->maxFileSizeInMB = $maxFileSizeInMB; + + return $this; + } + + public function type(): string + { + return 'image'; + } + + public function toArray(): array + { + return array_merge(parent::toArray(), [ + 'hasLegend' => $this->hasLegend, + 'fileFilter' => $this->fileFilter, + 'maxFileSize' => $this->maxFileSizeInMB, + ]); + } +} diff --git a/src/OzuCms/Form/OzuImageListField.php b/src/OzuCms/Form/OzuImageListField.php new file mode 100644 index 0000000..27e30da --- /dev/null +++ b/src/OzuCms/Form/OzuImageListField.php @@ -0,0 +1,11 @@ +options = $options; + + return $this; + } + + public function setDisplayAsDropdown(): self + { + $this->display = 'dropdown'; + + return $this; + } + + public function setDisplayAsList(): self + { + $this->display = 'list'; + + return $this; + } + + public function setMultiple(bool $multiple = true): self + { + $this->multiple = $multiple; + + return $this; + } + + public function setClearable(bool $clearable = true): self + { + $this->clearable = $clearable; + + return $this; + } + + public function type(): string + { + return 'select'; + } + + public function toArray(): array + { + return array_merge(parent::toArray(), [ + 'multiple' => $this->multiple, + 'display' => $this->display, + 'clearable' => $this->clearable, + 'options' => $this->options, + ]); + } +} diff --git a/src/OzuCms/Form/OzuTextField.php b/src/OzuCms/Form/OzuTextField.php new file mode 100644 index 0000000..0196463 --- /dev/null +++ b/src/OzuCms/Form/OzuTextField.php @@ -0,0 +1,11 @@ +key; + } + + public function size(): int + { + return $this->size; + } + + abstract public function type(): string; + + public function label(): ?string + { + return $this->label; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } + + public function setDefaultSort(string $direction = 'asc'): self + { + $this->isDefaultSort = true; + $this->sortDirection = $direction; + + return $this; + } + + public function isDefaultSort(): bool + { + return $this->isDefaultSort; + } + + public function getDefaultSortDirection(): string + { + return $this->sortDirection; + } +} diff --git a/src/OzuCms/List/OzuDateColumn.php b/src/OzuCms/List/OzuDateColumn.php new file mode 100644 index 0000000..f5ff685 --- /dev/null +++ b/src/OzuCms/List/OzuDateColumn.php @@ -0,0 +1,22 @@ +format = $format; + + return $this; + } + + public function type(): string + { + return 'date'; + } +} diff --git a/src/OzuCms/List/OzuTextColumn.php b/src/OzuCms/List/OzuTextColumn.php new file mode 100644 index 0000000..4cd823e --- /dev/null +++ b/src/OzuCms/List/OzuTextColumn.php @@ -0,0 +1,11 @@ +label = $label; + + return $this; + } + + public function setIcon(string $icon): self + { + $this->icon = $icon; + + return $this; + } + + public function setHasPublicationState(bool $hasState = true): self + { + $this->hasPublicationState = $hasState; + + return $this; + } + + public function setIsCreatable(bool $isCreatable = true): self + { + $this->isCreatable = $isCreatable; + + return $this; + } + + public function setIsDeletable(bool $isDeletable = true): self + { + $this->isDeletable = $isDeletable; + + return $this; + } + + public function label(): string + { + return $this->label; + } + + public function icon(): string + { + return $this->icon; + } + + public function hasPublicationState(): bool + { + return $this->hasPublicationState; + } + + public function isCreatable(): bool + { + return $this->isCreatable; + } + + public function isDeletable(): bool + { + return $this->isDeletable; + } +} diff --git a/src/OzuCms/OzuCollectionFormConfig.php b/src/OzuCms/OzuCollectionFormConfig.php new file mode 100644 index 0000000..7539867 --- /dev/null +++ b/src/OzuCms/OzuCollectionFormConfig.php @@ -0,0 +1,23 @@ +fields[] = $field; + + return $this; + } + + public function customFields(): Collection + { + return collect($this->fields); + } +} diff --git a/src/OzuCms/OzuCollectionListConfig.php b/src/OzuCms/OzuCollectionListConfig.php new file mode 100644 index 0000000..42d359e --- /dev/null +++ b/src/OzuCms/OzuCollectionListConfig.php @@ -0,0 +1,62 @@ +isReorderable = $isReorderable; + + return $this; + } + + public function setIsSearchable(bool $isSearchable = true): self + { + $this->isSearchable = $isSearchable; + + return $this; + } + + public function setIsPaginated(bool $isPaginated = true): self + { + $this->isPaginated = $isPaginated; + + return $this; + } + + public function addColumn(OzuColumn $column): self + { + $this->columns[] = $column; + + return $this; + } + + public function isReorderable(): bool + { + return $this->isReorderable; + } + + public function isSearchable(): bool + { + return $this->isSearchable; + } + + public function isPaginated(): bool + { + return $this->isPaginated; + } + + public function columns(): Collection + { + return collect($this->columns); + } +} diff --git a/src/OzuServiceProvider.php b/src/OzuServiceProvider.php new file mode 100644 index 0000000..82b9fb8 --- /dev/null +++ b/src/OzuServiceProvider.php @@ -0,0 +1,86 @@ +name('ozu-client') + ->hasMigrations(['create_ozu_tables'])->runsMigrations() + ->hasCommands([ + Console\ConfigureCmsCommand::class, + ]) + ->hasConfigFile(); + } + + public function register() + { + parent::register(); + + $this->app->singleton(Client::class, function () { + return new Client( + apiHost: config('ozu-client.api_host'), + apiKey: config('ozu-client.api_key'), + apiVersion: config('ozu-client.api_version'), + websiteKey: config('ozu-client.website_key'), + ); + }); + + $this->app->bind(Paginator::class, StaticPaginator::class); + $this->app->bind(LengthAwarePaginator::class, StaticLengthAwarePaginator::class); + $this->app->bind(Thumbnail::class, function ($app) { + return $app->environment('production') + ? $app->make(CdnThumbnail::class) + : $app->make(LocalThumbnail::class); + }); + + $this->app->register(DeployServiceProvider::class); + } + + public function boot() + { + parent::boot(); + + $this->loadViewsFrom(__DIR__.'/../resources/views', 'ozu'); + + $this->publishes([ + __DIR__.'/../resources/views/components/file.blade.php' => resource_path('views/vendor/ozu/components/file.blade.php'), + __DIR__.'/../resources/views/components/image.blade.php' => resource_path('views/vendor/ozu/components/image.blade.php'), + ], 'ozu-views'); + + Blade::componentNamespace('Code16\\OzuClient\\View\\Components\\Content', 'ozu-content'); + Blade::component(Content::class, 'ozu-content'); + Blade::component(Image::class, 'ozu-image'); + Blade::component(File::class, 'ozu-file'); + + Paginator::currentPageResolver(function () { + return request()->route()->parameter('page'); + }); + + Relation::enforceMorphMap( + collect(config('ozu-client.collections')) + ->mapWithKeys(fn ($className) => [ + (new $className)->ozuCollectionKey() => $className + ]) + ->toArray() + ); + } +} diff --git a/src/Services/Auth/PreviewGuard.php b/src/Services/Auth/PreviewGuard.php deleted file mode 100644 index 422f493..0000000 --- a/src/Services/Auth/PreviewGuard.php +++ /dev/null @@ -1,30 +0,0 @@ -session->has('jocko_preview_auth'); - } - - public function user() - { - return null; - } - - public function validate(array $credentials = []) - { - } -} diff --git a/src/Support/Database/MigratesOzuTable.php b/src/Support/Database/MigratesOzuTable.php new file mode 100644 index 0000000..849bd5a --- /dev/null +++ b/src/Support/Database/MigratesOzuTable.php @@ -0,0 +1,20 @@ +id(); + $table->text('title')->nullable(); + $table->text('content')->nullable(); + $table->string('slug')->nullable(); + $table->unsignedInteger('order')->default(1000); + $table->timestamps(); + }); + } +} diff --git a/src/Support/Database/OzuSeeder.php b/src/Support/Database/OzuSeeder.php new file mode 100644 index 0000000..ff00cb8 --- /dev/null +++ b/src/Support/Database/OzuSeeder.php @@ -0,0 +1,19 @@ +filter(fn ($file) => !in_array($file, ['.', '..'])) + ->each(fn ($file) => unlink($mediaDirectory . '/' . $file)); + } + } +} diff --git a/src/Support/Image.php b/src/Support/Image.php index 1d699c4..4b6007e 100644 --- a/src/Support/Image.php +++ b/src/Support/Image.php @@ -1,6 +1,6 @@ generateUrlParameters($width, $height, $fit), + $this->mediaModel->file_name + ); + } + + private function generateUrlParameters(?int $width, ?int $height, bool $fit): string + { + if (!$fit) { + if ($width && $height) { + return sprintf('tr:w-%s,h-%s,c-at_max', $width, $height); + } + if ($width) { + return sprintf('tr:w-%s', $width); + } + return sprintf('tr:h-%s', $height ?: 400); + } + + if ($width && $height) { + return sprintf('tr:w-%s,h-%s,c-at_max', $width, $height); + } + + $side = ($width ?: $height) ?: 400; + + return sprintf('tr:w-%s,h-%s,c-maintain_ratio', $side, $side); + } +} diff --git a/src/Support/Thumbnails/LocalThumbnail.php b/src/Support/Thumbnails/LocalThumbnail.php new file mode 100644 index 0000000..6da889c --- /dev/null +++ b/src/Support/Thumbnails/LocalThumbnail.php @@ -0,0 +1,87 @@ +imageManager = new ImageManager(new Driver()); + $this->storage = app(FilesystemManager::class); + } + + public function make(?int $width, ?int $height = null, bool $fit = false): ?string + { + if (! $this->mediaModel->disk || ! $this->mediaModel->file_name) { + return null; + } + + $this->width = $width ?: null; + $this->height = $height ?: null; + $this->fit = $fit; + + $thumbnailPath = sprintf( + 'thumbnails/%s/%s-%s_f%s_q-%s/%s', + dirname($this->mediaModel->file_name), + $width, + $height, + $fit ? '1' : '0', + $this->quality, + basename($this->mediaModel->file_name), + ); + + // Strip double / + $thumbnailPath = Str::replace('//', '/', $thumbnailPath); + + return $this->generateThumbnail( + $this->mediaModel->disk, + $this->mediaModel->file_name, + $thumbnailPath, + ); + } + + private function generateThumbnail(string $sourceDisk, string $sourceRelPath, string $thumbnailPath): ?string + { + $thumbnailDisk = $this->storage->disk('public'); + + if (!$thumbnailDisk->exists($thumbnailPath)) { + // Create thumbnail directories if needed + if (! $thumbnailDisk->exists(dirname($thumbnailPath))) { + $thumbnailDisk->makeDirectory(dirname($thumbnailPath)); + } + + try { + $sourceImg = $this->imageManager->read( + $this->storage->disk($sourceDisk)->get($sourceRelPath), + ); + + if ($this->fit) { + $sourceImg->cover($this->width, $this->height ?: $this->width); + } else { + $sourceImg->scaleDown($this->width, $this->height); + } + + $thumbnailDisk->put($thumbnailPath, $sourceImg->toJpeg(quality: $this->quality)); + } catch (FileNotFoundException $ex) { + return null; + } + } + + return $thumbnailDisk->url($thumbnailPath) + .($this->appendTimestamp ? '?'.$thumbnailDisk->lastModified($thumbnailPath) : ''); + } +} diff --git a/src/Support/Thumbnails/Thumbnail.php b/src/Support/Thumbnails/Thumbnail.php new file mode 100644 index 0000000..4546578 --- /dev/null +++ b/src/Support/Thumbnails/Thumbnail.php @@ -0,0 +1,19 @@ +mediaModel = $model; + + return $this; + } + + abstract public function make(?int $width, ?int $height = null, bool $fit = false): ?string; +} diff --git a/src/Support/WebsiteSettings.php b/src/Support/WebsiteSettings.php index 30a533e..ea2fdf9 100644 --- a/src/Support/WebsiteSettings.php +++ b/src/Support/WebsiteSettings.php @@ -1,8 +1,8 @@ loadValues(); +// $this->loadValues(); } private function loadValues(): self @@ -20,15 +20,15 @@ private function loadValues(): self return $this; } -// if(!Jocko::shouldCache()) { -// Cache::forget('jocko-settings'); +// if(!Ozu::shouldCache()) { +// Cache::forget('ozu-settings'); // } // -// $values = Cache::rememberForever('jocko-settings', function () { -// return Jocko::getSettings(); +// $values = Cache::rememberForever('ozu-settings', function () { +// return Ozu::getSettings(); // }); - $values = Jocko::getSettings(); + $values = Ozu::getSettings(); $this->loaded = true; diff --git a/src/View/Components/Content.php b/src/View/Components/Content.php index 5c2747f..a38c9ac 100644 --- a/src/View/Components/Content.php +++ b/src/View/Components/Content.php @@ -1,6 +1,6 @@ contentComponentAttributes->put('jocko-image', [ + $this->contentComponentAttributes->put('ozu-image', [ 'thumbnail-width' => $this->imageThumbnailWidth, 'thumbnail-height' => $this->imageThumbnailHeight, ]); diff --git a/src/View/Components/Content/Attributes.php b/src/View/Components/Content/Attributes.php index 2b2e6ae..d9a7254 100644 --- a/src/View/Components/Content/Attributes.php +++ b/src/View/Components/Content/Attributes.php @@ -1,6 +1,6 @@ image = \Code16\JockoClient\Support\Image::make($src); + $this->image = \Code16\OzuClient\Support\Image::make($src); } public function render(): View { - return view('jocko::components.image'); + return view('ozu::components.image'); } } diff --git a/tests/Pest.php b/tests/Pest.php index 09429b0..ac69839 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,5 @@ in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php index a83f495..8def12b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,8 +1,8 @@ 'Code16\\JockoClient\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn (string $modelName) => 'Code16\\OzuClient\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } protected function getPackageProviders($app) { return [ - JockoServiceProvider::class, + OzuServiceProvider::class, ]; } @@ -29,7 +29,7 @@ public function getEnvironmentSetUp($app) config()->set('database.default', 'testing'); /* - $migration = include __DIR__.'/../database/migrations/create_jocko-client_table.php.stub'; + $migration = include __DIR__.'/../database/migrations/create_ozu-client_table.php.stub'; $migration->up(); */ }