From 21b5cf9e0057f8337628215d8772f3cae4036331 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 23 Aug 2025 12:04:35 +0200 Subject: [PATCH 01/25] Correctly check for search driver --- app/External/Import/FromDataPack.php | 10 ++++++---- app/Models/Bar.php | 5 +---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/External/Import/FromDataPack.php b/app/External/Import/FromDataPack.php index f6b5bdf7..321dbd79 100644 --- a/app/External/Import/FromDataPack.php +++ b/app/External/Import/FromDataPack.php @@ -76,10 +76,12 @@ public function process(Filesystem $dataDisk, Bar $bar, User $user, ?BarOptionsE $bar->setStatus(BarStatusEnum::Active)->save(); - /** @phpstan-ignore-next-line */ - Ingredient::where('bar_id', $bar->id)->searchable(); - /** @phpstan-ignore-next-line */ - Cocktail::where('bar_id', $bar->id)->searchable(); + if (!empty(config('scout.driver'))) { + /** @phpstan-ignore-next-line */ + Ingredient::where('bar_id', $bar->id)->searchable(); + /** @phpstan-ignore-next-line */ + Cocktail::where('bar_id', $bar->id)->searchable(); + } $timerEnd = microtime(true); diff --git a/app/Models/Bar.php b/app/Models/Bar.php index 8d7701d8..56138263 100644 --- a/app/Models/Bar.php +++ b/app/Models/Bar.php @@ -40,10 +40,7 @@ public function getUploadPath(): string protected static function booted(): void { static::retrieved(function (Bar $bar) { - if ( - $bar->search_token || - config('scout.driver') === null - ) { + if (!empty($bar->search_token) || empty(config('scout.driver'))) { return; } From 9a2ba5d43056cc076fa9f4e2f853da2ddea1c327 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 23 Aug 2025 12:33:21 +0200 Subject: [PATCH 02/25] Check if scout driver is available --- app/Http/Controllers/GlassController.php | 4 +++- app/Http/Controllers/RatingController.php | 8 ++++++-- app/Http/Controllers/TagController.php | 8 ++++++-- app/Models/Glass.php | 5 ++++- app/Services/BarOptimizerService.php | 10 ++++++---- app/Services/IngredientService.php | 4 +++- config/scout.php | 2 +- 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/app/Http/Controllers/GlassController.php b/app/Http/Controllers/GlassController.php index 44eccd91..7a7497d1 100644 --- a/app/Http/Controllers/GlassController.php +++ b/app/Http/Controllers/GlassController.php @@ -132,7 +132,9 @@ public function update(int $id, GlassRequest $request): JsonResource } } - $glass->cocktails->each(fn ($cocktail) => $cocktail->searchable()); + if (!empty(config('scout.driver'))) { + $glass->cocktails->each(fn ($cocktail) => $cocktail->searchable()); + } return new GlassResource($glass); } diff --git a/app/Http/Controllers/RatingController.php b/app/Http/Controllers/RatingController.php index 2eedd927..2f0889d3 100644 --- a/app/Http/Controllers/RatingController.php +++ b/app/Http/Controllers/RatingController.php @@ -39,7 +39,9 @@ public function rateCocktail(RatingRequest $request, int $id): Response $request->user()->id ); - $cocktail->searchable(); + if (!empty(config('scout.driver'))) { + $cocktail->searchable(); + } return new Response(null, 204); } @@ -60,7 +62,9 @@ public function deleteCocktailRating(Request $request, int $id): Response $cocktail->deleteUserRating($request->user()->id); - $cocktail->searchable(); + if (!empty(config('scout.driver'))) { + $cocktail->searchable(); + } return new Response(null, 204); } diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index 387be505..0f49a98d 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -106,7 +106,9 @@ public function update(TagRequest $request, int $id): JsonResource $tag->save(); $cocktailIds = DB::table('cocktail_tag')->select('cocktail_id')->where('tag_id', $tag->id)->pluck('cocktail_id'); - Cocktail::find($cocktailIds)->each(fn ($cocktail) => $cocktail->searchable()); + if (!empty(config('scout.driver'))) { + Cocktail::find($cocktailIds)->each(fn ($cocktail) => $cocktail->searchable()); + } return new TagResource($tag); } @@ -127,7 +129,9 @@ public function delete(Request $request, int $id): Response $cocktailIds = DB::table('cocktail_tag')->select('cocktail_id')->where('tag_id', $id)->pluck('cocktail_id'); $tag->delete(); - Cocktail::find($cocktailIds)->each(fn ($cocktail) => $cocktail->searchable()); + if (!empty(config('scout.driver'))) { + Cocktail::find($cocktailIds)->each(fn ($cocktail) => $cocktail->searchable()); + } return new Response(null, 204); } diff --git a/app/Models/Glass.php b/app/Models/Glass.php index 2c644eaf..f703d0b4 100644 --- a/app/Models/Glass.php +++ b/app/Models/Glass.php @@ -73,7 +73,10 @@ public function bar(): BelongsTo public function delete(): bool { - $this->cocktails->each(fn ($cocktail) => $cocktail->searchable()); + if (!empty(config('scout.driver'))) { + $this->cocktails->each(fn ($cocktail) => $cocktail->searchable()); + } + $this->deleteImages(); return parent::delete(); diff --git a/app/Services/BarOptimizerService.php b/app/Services/BarOptimizerService.php index f2568d57..075ee3b5 100644 --- a/app/Services/BarOptimizerService.php +++ b/app/Services/BarOptimizerService.php @@ -73,10 +73,12 @@ public function optimize(int $barId): void } Log::info('[' . $barId . '] Finished updating ingredient default units.'); - /** @phpstan-ignore-next-line */ - Cocktail::where('bar_id', $barId)->searchable(); - /** @phpstan-ignore-next-line */ - Ingredient::where('bar_id', $barId)->searchable(); + if (!empty(config('scout.driver'))) { + /** @phpstan-ignore-next-line */ + Cocktail::where('bar_id', $barId)->searchable(); + /** @phpstan-ignore-next-line */ + Ingredient::where('bar_id', $barId)->searchable(); + } Log::info('[' . $barId . '] Finished re-indexing cocktails and ingredients.'); } diff --git a/app/Services/IngredientService.php b/app/Services/IngredientService.php index 0008cbbf..52a1668b 100644 --- a/app/Services/IngredientService.php +++ b/app/Services/IngredientService.php @@ -198,7 +198,9 @@ public function updateIngredient(int $id, IngredientRequest $dto): Ingredient }); } - $ingredient->cocktails->each(fn ($cocktail) => $cocktail->searchable()); + if (!empty(config('scout.driver'))) { + $ingredient->cocktails->each(fn ($cocktail) => $cocktail->searchable()); + } return $ingredient; } diff --git a/config/scout.php b/config/scout.php index 58b2203a..a452516c 100644 --- a/config/scout.php +++ b/config/scout.php @@ -15,7 +15,7 @@ | */ - 'driver' => env('SCOUT_DRIVER', 'algolia'), + 'driver' => env('SCOUT_DRIVER', null), /* |-------------------------------------------------------------------------- From 15afed7a79d80381bfbc4b2ba3d241cbeccab026 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 23 Aug 2025 17:14:41 +0200 Subject: [PATCH 03/25] Split menu request --- app/Http/Controllers/MenuController.php | 18 ++++---- app/Models/Menu.php | 31 ++++++------- app/OpenAPI/Schemas/MenuItemRequest.php | 43 ++++++++++++++++++ app/OpenAPI/Schemas/MenuRequest.php | 57 ++++++++++++++++++------ docs/openapi-generated.yaml | 58 +++++++++++++------------ 5 files changed, 141 insertions(+), 66 deletions(-) create mode 100644 app/OpenAPI/Schemas/MenuItemRequest.php diff --git a/app/Http/Controllers/MenuController.php b/app/Http/Controllers/MenuController.php index 69f91310..ef877353 100644 --- a/app/Http/Controllers/MenuController.php +++ b/app/Http/Controllers/MenuController.php @@ -15,8 +15,9 @@ use Kami\Cocktail\Rules\ResourceBelongsToBar; use Kami\Cocktail\Http\Resources\MenuResource; use Illuminate\Http\Resources\Json\JsonResource; -use Kami\Cocktail\Models\Enums\MenuItemTypeEnum; +use Kami\Cocktail\OpenAPI\Schemas\MenuItemRequest; use Kami\Cocktail\Http\Resources\MenuPublicResource; +use Kami\Cocktail\OpenAPI\Schemas\MenuRequest as SchemasMenuRequest; class MenuController extends Controller { @@ -98,27 +99,26 @@ public function update(MenuRequest $request): MenuResource abort(403); } - /** @var array */ - $items = $request->input('items', []); + $schemaRequest = SchemasMenuRequest::fromIlluminateRequest($request); - $ingredients = collect($items)->where('type', MenuItemTypeEnum::Ingredient->value)->values()->toArray(); - $cocktails = collect($items)->where('type', MenuItemTypeEnum::Cocktail->value)->values()->toArray(); + $ingredients = $schemaRequest->getIngredients(); + $cocktails = $schemaRequest->getCocktails(); - Validator::make($ingredients, [ + Validator::make(collect($ingredients)->map(fn (MenuItemRequest $mi) => ['id' => $mi->id])->toArray(), [ '*.id' => [new ResourceBelongsToBar(bar()->id, 'ingredients')], ])->validate(); - Validator::make($cocktails, [ + Validator::make(collect($cocktails)->map(fn (MenuItemRequest $mi) => ['id' => $mi->id])->toArray(), [ '*.id' => [new ResourceBelongsToBar(bar()->id, 'cocktails')], ])->validate(); $menu = Menu::firstOrCreate(['bar_id' => bar()->id]); - $menu->is_enabled = $request->boolean('is_enabled'); + $menu->is_enabled = $schemaRequest->isEnabled; if (!$menu->created_at) { $menu->created_at = now(); } $menu->updated_at = now(); - $menu->syncItems($items); + $menu->syncItems($schemaRequest->items); $menu->save(); return new MenuResource($menu); diff --git a/app/Models/Menu.php b/app/Models/Menu.php index 1f38f0c6..e57bc7f9 100644 --- a/app/Models/Menu.php +++ b/app/Models/Menu.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Model; use Kami\Cocktail\Models\ValueObjects\MenuItem; use Kami\Cocktail\Models\Enums\MenuItemTypeEnum; +use Kami\Cocktail\OpenAPI\Schemas\MenuItemRequest; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -61,7 +62,7 @@ public function getMenuItems(): Collection } /** - * @param array> $menuItems + * @param array $menuItems */ public function syncItems(array $menuItems): void { @@ -70,33 +71,33 @@ public function syncItems(array $menuItems): void foreach ($menuItems as $menuItem) { $price = 0; - if ($menuItem['price'] ?? false) { + if ($menuItem->price ?? false) { $price = Money::of( - $menuItem['price'], - $menuItem['currency'], + $menuItem->price, + $menuItem->currency, roundingMode: RoundingMode::UP )->getMinorAmount()->toInt(); } - if (MenuItemTypeEnum::from($menuItem['type']) === MenuItemTypeEnum::Ingredient) { - $currentIngredientMenuItems[] = $menuItem['id']; + if ($menuItem->type === MenuItemTypeEnum::Ingredient) { + $currentIngredientMenuItems[] = $menuItem->id; $this->menuIngredients()->updateOrCreate([ - 'ingredient_id' => $menuItem['id'] + 'ingredient_id' => $menuItem->id ], [ - 'category_name' => $menuItem['category_name'], - 'sort' => $menuItem['sort'] ?? 0, + 'category_name' => $menuItem->categoryName, + 'sort' => $menuItem->sort ?? 0, 'price' => $price, - 'currency' => $menuItem['currency'] ?? null, + 'currency' => $menuItem->currency ?? null, ]); } else { - $currentCocktailMenuItems[] = $menuItem['id']; + $currentCocktailMenuItems[] = $menuItem->id; $this->menuCocktails()->updateOrCreate([ - 'cocktail_id' => $menuItem['id'] + 'cocktail_id' => $menuItem->id ], [ - 'category_name' => $menuItem['category_name'], - 'sort' => $menuItem['sort'] ?? 0, + 'category_name' => $menuItem->categoryName, + 'sort' => $menuItem->sort ?? 0, 'price' => $price, - 'currency' => $menuItem['currency'] ?? null, + 'currency' => $menuItem->currency ?? null, ]); } } diff --git a/app/OpenAPI/Schemas/MenuItemRequest.php b/app/OpenAPI/Schemas/MenuItemRequest.php new file mode 100644 index 00000000..063c93e3 --- /dev/null +++ b/app/OpenAPI/Schemas/MenuItemRequest.php @@ -0,0 +1,43 @@ + $input + */ + public static function fromArray(array $input): self + { + return new self( + id: (int) $input['id'], + type: MenuItemTypeEnum::from($input['type']), + categoryName: $input['category_name'], + sort: (int) $input['sort'], + price: (float) $input['price'], + currency: $input['currency'] ?? 'EUR', + ); + } +} diff --git a/app/OpenAPI/Schemas/MenuRequest.php b/app/OpenAPI/Schemas/MenuRequest.php index 422f4fe4..9045bdb8 100644 --- a/app/OpenAPI/Schemas/MenuRequest.php +++ b/app/OpenAPI/Schemas/MenuRequest.php @@ -4,23 +4,52 @@ namespace Kami\Cocktail\OpenAPI\Schemas; +use Illuminate\Http\Request; use OpenApi\Attributes as OAT; -use Kami\Cocktail\Models\Enums\MenuItemTypeEnum; #[OAT\Schema(required: ['is_enabled', 'items'])] class MenuRequest { - #[OAT\Property(property: 'is_enabled')] - public bool $isEnabled = false; - /** @var array */ - #[OAT\Property(type: 'array', items: new OAT\Items(type: 'object', properties: [ - new OAT\Property(type: 'integer', property: 'id', example: 1), - new OAT\Property(type: 'schema', property: 'type', ref: MenuItemTypeEnum::class), - new OAT\Property(type: 'string', property: 'category_name', example: 'Category name'), - new OAT\Property(type: 'integer', property: 'sort', example: 1), - new OAT\Property(type: 'integer', property: 'price', example: 2252, format: 'minor'), - new OAT\Property(type: 'string', property: 'currency', example: 'EUR', format: 'ISO 4217'), - ], required: ['id', 'type', 'category_name', 'sort', 'price', 'currency'])), - ] - public array $items = []; + /** + * @param array $items + */ + public function __construct( + #[OAT\Property(property: 'is_enabled')] + public bool $isEnabled = false, + #[OAT\Property(items: new OAT\Items(type: MenuItemRequest::class))] + public array $items = [], + ) { + } + + public static function fromIlluminateRequest(Request $request): self + { + /** @var array */ + $formItems = $request->post('items', []); + + $items = []; + foreach ($formItems as $formItem) { + $items[] = MenuItemRequest::fromArray($formItem); + } + + return new self( + isEnabled: $request->boolean('is_enabled', false), + items: $items, + ); + } + + /** + * @return array + */ + public function getIngredients(): array + { + return array_filter($this->items, fn (MenuItemRequest $item) => $item->type === \Kami\Cocktail\Models\Enums\MenuItemTypeEnum::Ingredient); + } + + /** + * @return array + */ + public function getCocktails(): array + { + return array_filter($this->items, fn (MenuItemRequest $item) => $item->type === \Kami\Cocktail\Models\Enums\MenuItemTypeEnum::Cocktail); + } } diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index 1110cff7..5bda6fca 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -11179,6 +11179,35 @@ components: - 'null' example: 'My device' type: object + MenuItemRequest: + required: + - id + - type + - category_name + - sort + - price + - currency + properties: + id: + type: integer + example: 1 + type: + $ref: '#/components/schemas/MenuItemTypeEnum' + category_name: + type: string + example: 'Category name' + sort: + type: integer + example: 1 + price: + type: number + format: float + example: 22.52 + currency: + type: string + format: 'ISO 4217' + example: EUR + type: object MenuRequest: required: - is_enabled @@ -11189,34 +11218,7 @@ components: items: type: array items: - required: - - id - - type - - category_name - - sort - - price - - currency - properties: - id: - type: integer - example: 1 - type: - $ref: '#/components/schemas/MenuItemTypeEnum' - category_name: - type: string - example: 'Category name' - sort: - type: integer - example: 1 - price: - type: integer - format: minor - example: 2252 - currency: - type: string - format: 'ISO 4217' - example: EUR - type: object + $ref: '#/components/schemas/MenuItemRequest' type: object NoteRequest: required: From c60093d804d1214e63109f95b7ce958a547b1990 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 23 Aug 2025 23:31:45 +0200 Subject: [PATCH 04/25] Force unit conversion for ingredients --- app/External/Export/ToDataPack.php | 6 +++--- app/External/Model/Ingredient.php | 10 ++++++++-- app/Models/ValueObjects/UnitValueObject.php | 5 +++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/External/Export/ToDataPack.php b/app/External/Export/ToDataPack.php index 10148dd1..81dedbce 100644 --- a/app/External/Export/ToDataPack.php +++ b/app/External/Export/ToDataPack.php @@ -65,7 +65,7 @@ public function process(int $barId, ?string $filename = null, ForceUnitConvertEn } $this->dumpCocktails($barId, $zip, $toUnits); - $this->dumpIngredients($barId, $zip); + $this->dumpIngredients($barId, $zip, $toUnits); $this->dumpBaseData($barId, $zip); $this->dumpCalculators($barId, $zip); @@ -111,13 +111,13 @@ private function dumpCocktails(int $barId, ZipArchive &$zip, ?Units $toUnits = n } } - private function dumpIngredients(int $barId, ZipArchive &$zip): void + private function dumpIngredients(int $barId, ZipArchive &$zip, ?Units $toUnits = null): void { $ingredients = Ingredient::with('images.imageable', 'calculator', 'prices.priceCategory', 'ingredientParts.ingredient.parentIngredient', 'ancestors', 'parentIngredient')->where('bar_id', $barId)->get(); /** @var Ingredient $ingredient */ foreach ($ingredients as $ingredient) { - $data = IngredientExternal::fromModel($ingredient, true); + $data = IngredientExternal::fromModel($ingredient, true, $toUnits); /** @var \Kami\Cocktail\Models\Image $img */ foreach ($ingredient->images as $img) { diff --git a/app/External/Model/Ingredient.php b/app/External/Model/Ingredient.php index 99d76e1e..99c696ef 100644 --- a/app/External/Model/Ingredient.php +++ b/app/External/Model/Ingredient.php @@ -5,6 +5,7 @@ namespace Kami\Cocktail\External\Model; use Kami\Cocktail\External\SupportsCSV; +use Kami\RecipeUtils\UnitConverter\Units; use Kami\Cocktail\External\SupportsDraft2; use Kami\Cocktail\Models\ComplexIngredient; use Kami\Cocktail\External\SupportsDataPack; @@ -41,7 +42,7 @@ private function __construct( ) { } - public static function fromModel(IngredientModel $model, bool $useFileURI = false): self + public static function fromModel(IngredientModel $model, bool $useFileURI = false, ?Units $toUnits = null): self { $images = $model->images->map(function (ImageModel $image) use ($useFileURI) { return Image::fromModel($image, $useFileURI); @@ -55,6 +56,11 @@ public static function fromModel(IngredientModel $model, bool $useFileURI = fals return IngredientPrice::fromModel($price); })->toArray(); + $defaultIngredientUnits = $model->getDefaultUnits()?->value; + if ($model->getDefaultUnits()?->isConvertable()) { + $defaultIngredientUnits = $toUnits->value; + } + return new self( id: $model->getExternalId(), name: $model->name, @@ -73,7 +79,7 @@ public static function fromModel(IngredientModel $model, bool $useFileURI = fals sugarContent: $model->sugar_g_per_ml, acidity: $model->acidity, distillery: $model->distillery, - units: $model->getDefaultUnits()?->value, + units: $defaultIngredientUnits, ); } diff --git a/app/Models/ValueObjects/UnitValueObject.php b/app/Models/ValueObjects/UnitValueObject.php index e99b2060..5edf86dd 100644 --- a/app/Models/ValueObjects/UnitValueObject.php +++ b/app/Models/ValueObjects/UnitValueObject.php @@ -78,6 +78,11 @@ public function isBarspoon(): bool return str_contains($this->value, 'spoon') || in_array($this->value, $matches, true); } + public function isConvertable(): bool + { + return in_array($this->value, ['ml', 'oz', 'cl'], true); + } + public function __toString(): string { return $this->value; From 308989bf974d090db3e7de4d8d0af2ecf64b975a Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 23 Aug 2025 23:37:23 +0200 Subject: [PATCH 05/25] Reuse method --- app/Services/BarOptimizerService.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Services/BarOptimizerService.php b/app/Services/BarOptimizerService.php index 075ee3b5..e80bd02c 100644 --- a/app/Services/BarOptimizerService.php +++ b/app/Services/BarOptimizerService.php @@ -9,6 +9,7 @@ use Kami\Cocktail\Models\Cocktail; use Illuminate\Support\Facades\Log; use Kami\Cocktail\Models\Ingredient; +use Kami\Cocktail\Models\ValueObjects\UnitValueObject; final class BarOptimizerService { @@ -21,7 +22,7 @@ public function optimize(int $barId): void { $bar = Bar::findOrFail($barId); $barSettings = $bar->settings ?? []; - $forceToUnits = $barSettings['default_units'] ?? null; + $forceToUnits = new UnitValueObject($barSettings['default_units'] ?? null); Log::info('[' . $barId . '] Starting bar optimization for bar ID: ' . $barId); @@ -54,12 +55,11 @@ public function optimize(int $barId): void ->values(); foreach ($unitsPerIngredient as $commonUnit) { - $ingredientUnits = $commonUnit->units; + $ingredientUnits = new UnitValueObject($commonUnit->units); // Force unit conversion if specified and the unit is convertible - if ($forceToUnits && $forceToUnits !== $ingredientUnits) { - $convertableUnits = ['ml', 'oz', 'cl']; - if (in_array($ingredientUnits, $convertableUnits) && in_array($forceToUnits, $convertableUnits)) { + if ($forceToUnits->value && $forceToUnits->value !== $ingredientUnits->value) { + if ($ingredientUnits->isConvertable() && $forceToUnits->isConvertable()) { $ingredientUnits = $forceToUnits; Log::debug('[' . $barId . '] Forcing unit conversion from ' . $commonUnit->units . ' to ' . $forceToUnits . ' for ingredient ID: ' . $commonUnit->ingredient_id); } @@ -69,7 +69,7 @@ public function optimize(int $barId): void ->where('id', $commonUnit->ingredient_id) ->where('bar_id', $barId) ->whereNull('units') - ->update(['units' => $ingredientUnits]); + ->update(['units' => $ingredientUnits->value]); } Log::info('[' . $barId . '] Finished updating ingredient default units.'); From ed6ac5872a753756a30758050508d3e1a1562c20 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 23 Aug 2025 23:40:33 +0200 Subject: [PATCH 06/25] Use constant --- app/Http/Resources/AmountFormats.php | 2 +- app/Models/ValueObjects/UnitValueObject.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Http/Resources/AmountFormats.php b/app/Http/Resources/AmountFormats.php index de26b71f..81633232 100644 --- a/app/Http/Resources/AmountFormats.php +++ b/app/Http/Resources/AmountFormats.php @@ -43,7 +43,7 @@ public function __construct(private readonly CocktailIngredient $cocktailIngredi public function jsonSerialize(): mixed { - $unitsToConvertTo = ['ml', 'oz', 'cl']; + $unitsToConvertTo = UnitValueObject::CONVERTABLE_UNITS; $formats = []; foreach ($unitsToConvertTo as $unitTo) { diff --git a/app/Models/ValueObjects/UnitValueObject.php b/app/Models/ValueObjects/UnitValueObject.php index 5edf86dd..e86479e6 100644 --- a/app/Models/ValueObjects/UnitValueObject.php +++ b/app/Models/ValueObjects/UnitValueObject.php @@ -15,6 +15,8 @@ /** @var array> */ public array $units; + public const CONVERTABLE_UNITS = ['ml', 'oz', 'cl']; + public function __construct( ?string $value, ) { @@ -80,7 +82,7 @@ public function isBarspoon(): bool public function isConvertable(): bool { - return in_array($this->value, ['ml', 'oz', 'cl'], true); + return in_array($this->value, self::CONVERTABLE_UNITS, true); } public function __toString(): string From 73ffc025c520817c9c3400a00de7af16cdc94c5a Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Wed, 27 Aug 2025 17:13:17 +0200 Subject: [PATCH 07/25] Use unit value object --- app/External/Import/FromDataPack.php | 2 +- app/External/Model/Ingredient.php | 13 +- app/Models/ValueObjects/UnitValueObject.php | 27 +- composer.json | 2 +- composer.lock | 320 +++++++++++--------- 5 files changed, 195 insertions(+), 169 deletions(-) diff --git a/app/External/Import/FromDataPack.php b/app/External/Import/FromDataPack.php index 321dbd79..d71b44cd 100644 --- a/app/External/Import/FromDataPack.php +++ b/app/External/Import/FromDataPack.php @@ -210,7 +210,7 @@ private function importIngredients(Filesystem $dataDisk, Bar $bar, User $user): 'sugar_g_per_ml' => $externalIngredient->sugarContent, 'acidity' => $externalIngredient->acidity, 'distillery' => $externalIngredient->distillery, - 'units' => $externalIngredient->units, + 'units' => $externalIngredient->units?->value, ]; if ($externalIngredient->parentId) { diff --git a/app/External/Model/Ingredient.php b/app/External/Model/Ingredient.php index 99c696ef..37ead5c0 100644 --- a/app/External/Model/Ingredient.php +++ b/app/External/Model/Ingredient.php @@ -12,6 +12,7 @@ use Kami\Cocktail\Models\Image as ImageModel; use Kami\Cocktail\Models\Ingredient as IngredientModel; use Kami\Cocktail\Models\IngredientPrice as IngredientPriceModel; +use Kami\Cocktail\Models\ValueObjects\UnitValueObject; readonly class Ingredient implements SupportsDataPack, SupportsDraft2, SupportsCSV { @@ -38,7 +39,7 @@ private function __construct( public ?float $sugarContent = null, public ?float $acidity = null, public ?string $distillery = null, - public ?string $units = null, + public ?UnitValueObject $units = null, ) { } @@ -56,9 +57,9 @@ public static function fromModel(IngredientModel $model, bool $useFileURI = fals return IngredientPrice::fromModel($price); })->toArray(); - $defaultIngredientUnits = $model->getDefaultUnits()?->value; + $defaultIngredientUnits = $model->getDefaultUnits(); if ($model->getDefaultUnits()?->isConvertable()) { - $defaultIngredientUnits = $toUnits->value; + $defaultIngredientUnits = new UnitValueObject($toUnits->value); } return new self( @@ -118,7 +119,7 @@ public static function fromDataPackArray(array $sourceArray): self sugarContent: $sourceArray['sugar_g_per_ml'] ?? null, acidity: $sourceArray['acidity'] ?? null, distillery: $sourceArray['distillery'] ?? null, - units: $sourceArray['units'] ?? null, + units: $sourceArray['units'] ? new UnitValueObject($sourceArray['units']) : null, ); } @@ -142,7 +143,7 @@ public function toDataPackArray(): array 'sugar_g_per_ml' => $this->sugarContent, 'acidity' => $this->acidity, 'distillery' => $this->distillery, - 'units' => $this->units, + 'units' => $this->units?->value, ]; } @@ -167,7 +168,7 @@ public static function fromCSV(array $sourceArray): self sugarContent: blank($sourceArray['sugar_g_per_ml']) ? null : $sourceArray['sugar_g_per_ml'], acidity: blank($sourceArray['acidity']) ? null : $sourceArray['acidity'], distillery: blank($sourceArray['distillery']) ? null : $sourceArray['distillery'], - units: blank($sourceArray['units']) ? null : $sourceArray['units'], + units: blank($sourceArray['units']) ? null : new UnitValueObject($sourceArray['units']), ); } diff --git a/app/Models/ValueObjects/UnitValueObject.php b/app/Models/ValueObjects/UnitValueObject.php index e86479e6..e8f34bab 100644 --- a/app/Models/ValueObjects/UnitValueObject.php +++ b/app/Models/ValueObjects/UnitValueObject.php @@ -6,6 +6,7 @@ use Stringable; use JsonSerializable; +use Kami\RecipeUtils\DefaultUnits; use Kami\RecipeUtils\UnitConverter\Units; final readonly class UnitValueObject implements Stringable, JsonSerializable @@ -20,31 +21,7 @@ public function __construct( ?string $value, ) { - // TODO: Move to package - $this->units = [ - 'oz' => ['oz.', 'fl-oz', 'oz', 'ounce', 'ounces'], - 'ml' => ['ml', 'ml.', 'milliliter', 'milliliters'], - 'cl' => ['cl', 'cl.', 'centiliter', 'centiliters'], - 'dash' => ['dashes', 'dash', 'ds'], - 'sprigs' => ['sprig', 'sprigs'], - 'leaves' => ['leaves', 'leaf'], - 'whole' => ['whole'], - 'drops' => ['drop', 'drops'], - 'barspoon' => ['barspoon', 'teaspoon', 'bsp', 'tsp', 'tsp.', 'tspn', 't', 't.', 'teaspoon', 'teaspoons', 'tablespoons', 'tablespoon'], - 'slice' => ['slice', 'sliced', 'slices'], - 'cup' => ['c', 'c.', 'cup', 'cups'], - 'pint' => ['pt', 'pts', 'pt.', 'pint', 'pints'], - 'splash' => ['a splash', 'splash', 'splashes'], - 'pinch' => ['pinches', 'pinch'], - 'topup' => ['topup'], - 'part' => ['part', 'parts'], - 'wedge' => ['wedge', 'wedges'], - 'cube' => ['cubes', 'cube'], - 'bottle' => ['bottles', 'bottle'], - 'can' => ['cans', 'can'], - 'bag' => ['bags', 'bag'], - 'shot' => ['shots', 'shot'], - ]; + $this->units = DefaultUnits::get(); $this->value = trim(mb_strtolower($value ?? '')); } diff --git a/composer.json b/composer.json index 08b4f9d5..bee27e6f 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "guzzlehttp/guzzle": "^7.2", "http-interop/http-factory-guzzle": "^1.2", "jcupitt/vips": "^2.4", - "karlomikus/recipe-utils": "^0.16", + "karlomikus/recipe-utils": "^0.17", "kevinrob/guzzle-cache-middleware": "^6.0", "laminas/laminas-feed": "^2.23", "laravel/cashier-paddle": "^2.0", diff --git a/composer.lock b/composer.lock index 43b27df6..45a2324b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "542ed20f3770dad61941fbf3a3c2adc7", + "content-hash": "832f605d9d287023e3ded62286dd19e0", "packages": [ { "name": "brick/math", @@ -765,22 +765,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.9.3", + "version": "7.10.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -871,7 +871,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" }, "funding": [ { @@ -887,20 +887,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:37:11+00:00" + "time": "2025-08-23T22:36:01+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { @@ -908,7 +908,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { @@ -954,7 +954,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.2.0" + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { @@ -970,20 +970,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:27:01+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + "reference": "21dc724a0583619cd1652f673303492272778051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -999,7 +999,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1070,7 +1070,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.1" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -1086,20 +1086,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T12:30:47+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.4", + "version": "v1.0.5", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1", "shasum": "" }, "require": { @@ -1108,7 +1108,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.44 || ^9.6.25", "uri-template/tests": "1.0.0" }, "type": "library", @@ -1156,7 +1156,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.5" }, "funding": [ { @@ -1172,7 +1172,7 @@ "type": "tidelift" } ], - "time": "2025-02-03T10:55:03+00:00" + "time": "2025-08-22T14:27:06+00:00" }, { "name": "http-interop/http-factory-guzzle", @@ -1355,16 +1355,16 @@ }, { "name": "karlomikus/recipe-utils", - "version": "0.16.0", + "version": "0.17.0", "source": { "type": "git", "url": "https://github.com/karlomikus/recipe-utils.git", - "reference": "e41949c25553ee458ae18483a934fc3cd3dc9403" + "reference": "4f8eac95619f99e29c4c6cc8e1ea30b942607372" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/karlomikus/recipe-utils/zipball/e41949c25553ee458ae18483a934fc3cd3dc9403", - "reference": "e41949c25553ee458ae18483a934fc3cd3dc9403", + "url": "https://api.github.com/repos/karlomikus/recipe-utils/zipball/4f8eac95619f99e29c4c6cc8e1ea30b942607372", + "reference": "4f8eac95619f99e29c4c6cc8e1ea30b942607372", "shasum": "" }, "require": { @@ -1398,9 +1398,9 @@ "description": "Utilities for extracting normalized ingredient data from recipes", "support": { "issues": "https://github.com/karlomikus/recipe-utils/issues", - "source": "https://github.com/karlomikus/recipe-utils/tree/0.16.0" + "source": "https://github.com/karlomikus/recipe-utils/tree/0.17.0" }, - "time": "2025-03-24T15:29:40+00:00" + "time": "2025-08-27T15:09:01+00:00" }, { "name": "kevinrob/guzzle-cache-middleware", @@ -1772,16 +1772,16 @@ }, { "name": "laravel/framework", - "version": "v12.24.0", + "version": "v12.26.3", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "6dcf2c46da23d159f35d6246234953a74b740d83" + "reference": "1a8e961a1801794c36c243bb610210d0a2bd61cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/6dcf2c46da23d159f35d6246234953a74b740d83", - "reference": "6dcf2c46da23d159f35d6246234953a74b740d83", + "url": "https://api.github.com/repos/laravel/framework/zipball/1a8e961a1801794c36c243bb610210d0a2bd61cb", + "reference": "1a8e961a1801794c36c243bb610210d0a2bd61cb", "shasum": "" }, "require": { @@ -1821,9 +1821,9 @@ "symfony/http-kernel": "^7.2.0", "symfony/mailer": "^7.2.0", "symfony/mime": "^7.2.0", - "symfony/polyfill-php83": "^1.31", - "symfony/polyfill-php84": "^1.31", - "symfony/polyfill-php85": "^1.31", + "symfony/polyfill-php83": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php85": "^1.33", "symfony/process": "^7.2.0", "symfony/routing": "^7.2.0", "symfony/uid": "^7.2.0", @@ -1985,20 +1985,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-08-13T20:30:36+00:00" + "time": "2025-08-27T13:51:06+00:00" }, { "name": "laravel/horizon", - "version": "v5.33.2", + "version": "v5.33.4", "source": { "type": "git", "url": "https://github.com/laravel/horizon.git", - "reference": "baa36725ed24dbbcd7ddb4ba3dcfd4c0f22028ed" + "reference": "678362049ce5b9ce96673ac0282bbfda3279eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/horizon/zipball/baa36725ed24dbbcd7ddb4ba3dcfd4c0f22028ed", - "reference": "baa36725ed24dbbcd7ddb4ba3dcfd4c0f22028ed", + "url": "https://api.github.com/repos/laravel/horizon/zipball/678362049ce5b9ce96673ac0282bbfda3279eca9", + "reference": "678362049ce5b9ce96673ac0282bbfda3279eca9", "shasum": "" }, "require": { @@ -2063,9 +2063,9 @@ ], "support": { "issues": "https://github.com/laravel/horizon/issues", - "source": "https://github.com/laravel/horizon/tree/v5.33.2" + "source": "https://github.com/laravel/horizon/tree/v5.33.4" }, - "time": "2025-08-05T02:30:15+00:00" + "time": "2025-08-25T13:31:24+00:00" }, { "name": "laravel/prompts", @@ -2192,16 +2192,16 @@ }, { "name": "laravel/scout", - "version": "v10.17.0", + "version": "v10.19.0", "source": { "type": "git", "url": "https://github.com/laravel/scout.git", - "reference": "66b064ab1f987560d1edfbc10f46557fddfed600" + "reference": "996b2a8b5ccc583e7df667c8aac924a46bc8bdd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/scout/zipball/66b064ab1f987560d1edfbc10f46557fddfed600", - "reference": "66b064ab1f987560d1edfbc10f46557fddfed600", + "url": "https://api.github.com/repos/laravel/scout/zipball/996b2a8b5ccc583e7df667c8aac924a46bc8bdd3", + "reference": "996b2a8b5ccc583e7df667c8aac924a46bc8bdd3", "shasum": "" }, "require": { @@ -2269,7 +2269,7 @@ "issues": "https://github.com/laravel/scout/issues", "source": "https://github.com/laravel/scout" }, - "time": "2025-07-22T15:54:45+00:00" + "time": "2025-08-26T14:24:24+00:00" }, { "name": "laravel/serializable-closure", @@ -4183,16 +4183,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", "shasum": "" }, "require": { @@ -4200,7 +4200,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -4242,7 +4242,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" }, "funding": [ { @@ -4254,7 +4254,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-08-21T11:53:16+00:00" }, { "name": "phpseclib/phpseclib", @@ -5046,16 +5046,16 @@ }, { "name": "sentry/sentry", - "version": "4.14.2", + "version": "4.15.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "bfeec74303d60d3f8bc33701ab3e86f8a8729f17" + "reference": "b2d84de69f3eda8ca22b0b00e9f923be3b837355" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/bfeec74303d60d3f8bc33701ab3e86f8a8729f17", - "reference": "bfeec74303d60d3f8bc33701ab3e86f8a8729f17", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/b2d84de69f3eda8ca22b0b00e9f923be3b837355", + "reference": "b2d84de69f3eda8ca22b0b00e9f923be3b837355", "shasum": "" }, "require": { @@ -5119,7 +5119,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.14.2" + "source": "https://github.com/getsentry/sentry-php/tree/4.15.0" }, "funding": [ { @@ -5131,7 +5131,7 @@ "type": "custom" } ], - "time": "2025-07-21T08:28:29+00:00" + "time": "2025-08-20T14:26:37+00:00" }, { "name": "sentry/sentry-laravel", @@ -7355,7 +7355,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -7414,7 +7414,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -7425,6 +7425,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7434,7 +7438,7 @@ }, { "name": "symfony/polyfill-iconv", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", @@ -7494,7 +7498,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.33.0" }, "funding": [ { @@ -7505,6 +7509,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7514,16 +7522,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -7572,7 +7580,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -7583,25 +7591,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "763d2a91fea5681509ca01acbc1c5e450d127811" + "reference": "bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/763d2a91fea5681509ca01acbc1c5e450d127811", - "reference": "763d2a91fea5681509ca01acbc1c5e450d127811", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c", + "reference": "bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c", "shasum": "" }, "require": { @@ -7656,7 +7668,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.33.0" }, "funding": [ { @@ -7667,16 +7679,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-21T18:38:29+00:00" + "time": "2025-06-20T22:24:30+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -7739,7 +7755,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -7750,6 +7766,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7759,7 +7779,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -7820,7 +7840,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -7831,6 +7851,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7840,7 +7864,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -7901,7 +7925,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -7912,6 +7936,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7986,7 +8014,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -8046,7 +8074,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -8057,6 +8085,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -8066,16 +8098,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -8122,7 +8154,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -8133,25 +8165,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { "name": "symfony/polyfill-php84", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "000df7860439609837bbe28670b0be15783b7fbf" + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf", - "reference": "000df7860439609837bbe28670b0be15783b7fbf", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", "shasum": "" }, "require": { @@ -8198,7 +8234,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" }, "funding": [ { @@ -8209,25 +8245,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-20T12:04:08+00:00" + "time": "2025-06-24T13:30:11+00:00" }, { "name": "symfony/polyfill-php85", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php85.git", - "reference": "6fedf31ce4e3648f4ff5ca58bfd53127d38f05fd" + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/6fedf31ce4e3648f4ff5ca58bfd53127d38f05fd", - "reference": "6fedf31ce4e3648f4ff5ca58bfd53127d38f05fd", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", "shasum": "" }, "require": { @@ -8274,7 +8314,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php85/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" }, "funding": [ { @@ -8285,16 +8325,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-02T08:40:52+00:00" + "time": "2025-06-23T16:12:55+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -8353,7 +8397,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -8364,6 +8408,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -9614,16 +9662,16 @@ }, { "name": "zircote/swagger-php", - "version": "5.2.0", + "version": "5.3.2", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "b82e160f9dcc9c5c5e59bf9a4904ed4a8ffa86a4" + "reference": "d8fa9dc4c3b2fc8651ae780021bb9719b1e63d40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/b82e160f9dcc9c5c5e59bf9a4904ed4a8ffa86a4", - "reference": "b82e160f9dcc9c5c5e59bf9a4904ed4a8ffa86a4", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/d8fa9dc4c3b2fc8651ae780021bb9719b1e63d40", + "reference": "d8fa9dc4c3b2fc8651ae780021bb9719b1e63d40", "shasum": "" }, "require": { @@ -9694,9 +9742,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/5.2.0" + "source": "https://github.com/zircote/swagger-php/tree/5.3.2" }, - "time": "2025-08-11T04:26:13+00:00" + "time": "2025-08-25T21:57:16+00:00" } ], "packages-dev": [ @@ -10013,16 +10061,16 @@ }, { "name": "larastan/larastan", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "6431d010dd383a9279eb8874a76ddb571738564a" + "reference": "3c223047e374befd1b64959784685d6ecccf66aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/6431d010dd383a9279eb8874a76ddb571738564a", - "reference": "6431d010dd383a9279eb8874a76ddb571738564a", + "url": "https://api.github.com/repos/larastan/larastan/zipball/3c223047e374befd1b64959784685d6ecccf66aa", + "reference": "3c223047e374befd1b64959784685d6ecccf66aa", "shasum": "" }, "require": { @@ -10090,7 +10138,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v3.6.0" + "source": "https://github.com/larastan/larastan/tree/v3.6.1" }, "funding": [ { @@ -10098,7 +10146,7 @@ "type": "github" } ], - "time": "2025-07-11T06:52:52+00:00" + "time": "2025-08-25T07:24:56+00:00" }, { "name": "laravel/pint", @@ -10662,16 +10710,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.10", + "version": "11.0.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1a800a7446add2d79cc6b3c01c45381810367d76" + "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76", - "reference": "1a800a7446add2d79cc6b3c01c45381810367d76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", + "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", "shasum": "" }, "require": { @@ -10728,7 +10776,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.11" }, "funding": [ { @@ -10748,7 +10796,7 @@ "type": "tidelift" } ], - "time": "2025-06-18T08:56:18+00:00" + "time": "2025-08-27T14:37:49+00:00" }, { "name": "phpunit/php-file-iterator", @@ -10997,16 +11045,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.32", + "version": "11.5.34", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "101e132dcf9e74a1eb3a309b4f686114ae8f7f36" + "reference": "3e4c6ef395f7cb61a6206c23e0e04b31724174f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/101e132dcf9e74a1eb3a309b4f686114ae8f7f36", - "reference": "101e132dcf9e74a1eb3a309b4f686114ae8f7f36", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e4c6ef395f7cb61a6206c23e0e04b31724174f2", + "reference": "3e4c6ef395f7cb61a6206c23e0e04b31724174f2", "shasum": "" }, "require": { @@ -11078,7 +11126,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.32" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.34" }, "funding": [ { @@ -11102,7 +11150,7 @@ "type": "tidelift" } ], - "time": "2025-08-12T07:32:49+00:00" + "time": "2025-08-20T14:41:45+00:00" }, { "name": "sebastian/cli-parser", From e1cd1e988eea6973744a79a7c89be1c277f4ef2c Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 30 Aug 2025 19:20:59 +0200 Subject: [PATCH 08/25] Use bar default units for ingredients --- app/External/Import/FromDataPack.php | 8 +++++++- app/External/Model/Ingredient.php | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/External/Import/FromDataPack.php b/app/External/Import/FromDataPack.php index d71b44cd..a0778ea7 100644 --- a/app/External/Import/FromDataPack.php +++ b/app/External/Import/FromDataPack.php @@ -194,6 +194,12 @@ private function importIngredients(Filesystem $dataDisk, Bar $bar, User $user): continue; } + $ingredientUnit = $externalIngredient->units?->value; + $barSettings = $bar->settings ?? []; + if ($externalIngredient->units?->isConvertable() && array_key_exists('default_units', $barSettings)) { + $ingredientUnit = $barSettings['default_units']; + } + $slug = $externalIngredient->id . '-' . $bar->id; $ingredientsToInsert[] = [ 'bar_id' => $bar->id, @@ -210,7 +216,7 @@ private function importIngredients(Filesystem $dataDisk, Bar $bar, User $user): 'sugar_g_per_ml' => $externalIngredient->sugarContent, 'acidity' => $externalIngredient->acidity, 'distillery' => $externalIngredient->distillery, - 'units' => $externalIngredient->units?->value, + 'units' => $ingredientUnit, ]; if ($externalIngredient->parentId) { diff --git a/app/External/Model/Ingredient.php b/app/External/Model/Ingredient.php index 37ead5c0..c12f64f6 100644 --- a/app/External/Model/Ingredient.php +++ b/app/External/Model/Ingredient.php @@ -119,7 +119,7 @@ public static function fromDataPackArray(array $sourceArray): self sugarContent: $sourceArray['sugar_g_per_ml'] ?? null, acidity: $sourceArray['acidity'] ?? null, distillery: $sourceArray['distillery'] ?? null, - units: $sourceArray['units'] ? new UnitValueObject($sourceArray['units']) : null, + units: ($sourceArray['units'] ?? null) ? new UnitValueObject($sourceArray['units']) : null, ); } From 5c346e6bae9604f79db848a3c1c4d74f5d66fbd7 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 30 Aug 2025 19:21:48 +0200 Subject: [PATCH 09/25] Update deps --- composer.lock | 207 +++++++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 97 deletions(-) diff --git a/composer.lock b/composer.lock index 45a2324b..35a2bfc5 100644 --- a/composer.lock +++ b/composer.lock @@ -1772,16 +1772,16 @@ }, { "name": "laravel/framework", - "version": "v12.26.3", + "version": "v12.26.4", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "1a8e961a1801794c36c243bb610210d0a2bd61cb" + "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/1a8e961a1801794c36c243bb610210d0a2bd61cb", - "reference": "1a8e961a1801794c36c243bb610210d0a2bd61cb", + "url": "https://api.github.com/repos/laravel/framework/zipball/085a367a32ba86fcfa647bfc796098ae6f795b09", + "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09", "shasum": "" }, "require": { @@ -1891,7 +1891,7 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^10.6.0", + "orchestra/testbench-core": "^10.6.3", "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", @@ -1985,7 +1985,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-08-27T13:51:06+00:00" + "time": "2025-08-29T14:15:53+00:00" }, { "name": "laravel/horizon", @@ -5046,16 +5046,16 @@ }, { "name": "sentry/sentry", - "version": "4.15.0", + "version": "4.15.1", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "b2d84de69f3eda8ca22b0b00e9f923be3b837355" + "reference": "0d09baf3700869ec4b723c95eb466de56c3d74b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/b2d84de69f3eda8ca22b0b00e9f923be3b837355", - "reference": "b2d84de69f3eda8ca22b0b00e9f923be3b837355", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/0d09baf3700869ec4b723c95eb466de56c3d74b6", + "reference": "0d09baf3700869ec4b723c95eb466de56c3d74b6", "shasum": "" }, "require": { @@ -5119,7 +5119,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.15.0" + "source": "https://github.com/getsentry/sentry-php/tree/4.15.1" }, "funding": [ { @@ -5131,7 +5131,7 @@ "type": "custom" } ], - "time": "2025-08-20T14:26:37+00:00" + "time": "2025-08-28T15:45:14+00:00" }, { "name": "sentry/sentry-laravel", @@ -6132,16 +6132,16 @@ }, { "name": "symfony/console", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1" + "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1", - "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1", + "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", + "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", "shasum": "" }, "require": { @@ -6206,7 +6206,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.2" + "source": "https://github.com/symfony/console/tree/v7.3.3" }, "funding": [ { @@ -6226,7 +6226,7 @@ "type": "tidelift" } ], - "time": "2025-07-30T17:13:41+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "symfony/css-selector", @@ -6362,16 +6362,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "8b2ee2e06ab99fa5f067b6699296d4e35c156bb9" + "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/8b2ee2e06ab99fa5f067b6699296d4e35c156bb9", - "reference": "8b2ee2e06ab99fa5f067b6699296d4e35c156bb9", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/efa076ea0eeff504383ff0dcf827ea5ce15690ba", + "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba", "shasum": "" }, "require": { @@ -6409,7 +6409,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.3.1" + "source": "https://github.com/symfony/dom-crawler/tree/v7.3.3" }, "funding": [ { @@ -6420,12 +6420,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-15T10:07:06+00:00" + "time": "2025-08-06T20:13:54+00:00" }, { "name": "symfony/error-handler", @@ -6510,16 +6514,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", "shasum": "" }, "require": { @@ -6570,7 +6574,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" }, "funding": [ { @@ -6581,12 +6585,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-22T09:11:45+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6734,16 +6742,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "1c064a0c67749923483216b081066642751cc2c7" + "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7", - "reference": "1c064a0c67749923483216b081066642751cc2c7", + "url": "https://api.github.com/repos/symfony/http-client/zipball/333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019", + "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019", "shasum": "" }, "require": { @@ -6751,6 +6759,7 @@ "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -6809,7 +6818,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.2" + "source": "https://github.com/symfony/http-client/tree/v7.3.3" }, "funding": [ { @@ -6829,7 +6838,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-08-27T07:45:05+00:00" }, { "name": "symfony/http-client-contracts", @@ -6911,16 +6920,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6" + "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6877c122b3a6cc3695849622720054f6e6fa5fa6", - "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00", + "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00", "shasum": "" }, "require": { @@ -6970,7 +6979,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.2" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.3" }, "funding": [ { @@ -6990,20 +6999,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:47:49+00:00" + "time": "2025-08-20T08:04:18+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c" + "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6ecc895559ec0097e221ed2fd5eb44d5fede083c", - "reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b", + "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b", "shasum": "" }, "require": { @@ -7088,7 +7097,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.2" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.3" }, "funding": [ { @@ -7108,20 +7117,20 @@ "type": "tidelift" } ], - "time": "2025-07-31T10:45:04+00:00" + "time": "2025-08-29T08:23:45+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" + "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", - "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575", + "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575", "shasum": "" }, "require": { @@ -7172,7 +7181,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.2" + "source": "https://github.com/symfony/mailer/tree/v7.3.3" }, "funding": [ { @@ -7192,7 +7201,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/mime", @@ -7284,16 +7293,16 @@ }, { "name": "symfony/options-resolver", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37" + "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37", - "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d", + "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d", "shasum": "" }, "require": { @@ -7331,7 +7340,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.2" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.3" }, "funding": [ { @@ -7351,7 +7360,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-08-05T10:16:07+00:00" }, { "name": "symfony/polyfill-ctype", @@ -8421,16 +8430,16 @@ }, { "name": "symfony/process", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "reference": "32241012d521e2e8a9d713adb0812bb773b907f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1", + "reference": "32241012d521e2e8a9d713adb0812bb773b907f1", "shasum": "" }, "require": { @@ -8462,7 +8471,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/process/tree/v7.3.3" }, "funding": [ { @@ -8473,12 +8482,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2025-08-18T09:42:54+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -8733,16 +8746,16 @@ }, { "name": "symfony/string", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", - "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", + "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", "shasum": "" }, "require": { @@ -8800,7 +8813,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.2" + "source": "https://github.com/symfony/string/tree/v7.3.3" }, "funding": [ { @@ -8820,20 +8833,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:47:49+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "symfony/translation", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" + "reference": "e0837b4cbcef63c754d89a4806575cada743a38d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", - "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", + "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d", + "reference": "e0837b4cbcef63c754d89a4806575cada743a38d", "shasum": "" }, "require": { @@ -8900,7 +8913,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.2" + "source": "https://github.com/symfony/translation/tree/v7.3.3" }, "funding": [ { @@ -8920,7 +8933,7 @@ "type": "tidelift" } ], - "time": "2025-07-30T17:31:46+00:00" + "time": "2025-08-01T21:02:37+00:00" }, { "name": "symfony/translation-contracts", @@ -9076,16 +9089,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "53205bea27450dc5c65377518b3275e126d45e75" + "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", - "reference": "53205bea27450dc5c65377518b3275e126d45e75", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", + "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", "shasum": "" }, "require": { @@ -9139,7 +9152,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.3" }, "funding": [ { @@ -9159,20 +9172,20 @@ "type": "tidelift" } ], - "time": "2025-07-29T20:02:46+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/yaml", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30" + "reference": "d4f4a66866fe2451f61296924767280ab5732d9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/b8d7d868da9eb0919e99c8830431ea087d6aae30", - "reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30", + "url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d", + "reference": "d4f4a66866fe2451f61296924767280ab5732d9d", "shasum": "" }, "require": { @@ -9215,7 +9228,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.2" + "source": "https://github.com/symfony/yaml/tree/v7.3.3" }, "funding": [ { @@ -9235,7 +9248,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:47:49+00:00" + "time": "2025-08-27T11:34:33+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -11045,16 +11058,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.34", + "version": "11.5.35", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3e4c6ef395f7cb61a6206c23e0e04b31724174f2" + "reference": "d341ee94ee5007b286fc7907b383aae6b5b3cc91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e4c6ef395f7cb61a6206c23e0e04b31724174f2", - "reference": "3e4c6ef395f7cb61a6206c23e0e04b31724174f2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d341ee94ee5007b286fc7907b383aae6b5b3cc91", + "reference": "d341ee94ee5007b286fc7907b383aae6b5b3cc91", "shasum": "" }, "require": { @@ -11068,7 +11081,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.10", + "phpunit/php-code-coverage": "^11.0.11", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", @@ -11126,7 +11139,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.34" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.35" }, "funding": [ { @@ -11150,7 +11163,7 @@ "type": "tidelift" } ], - "time": "2025-08-20T14:41:45+00:00" + "time": "2025-08-28T05:13:54+00:00" }, { "name": "sebastian/cli-parser", From 38dff012233ce99c2b88cd10e4266fbf936fdf60 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 30 Aug 2025 19:29:25 +0200 Subject: [PATCH 10/25] Prevent duplicate shelf ingredients in batch store --- app/Http/Controllers/ShelfController.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/Http/Controllers/ShelfController.php b/app/Http/Controllers/ShelfController.php index 79e3c64c..8e945e29 100644 --- a/app/Http/Controllers/ShelfController.php +++ b/app/Http/Controllers/ShelfController.php @@ -262,7 +262,9 @@ public function batchStoreBarIngredients(ShelfIngredientsRequest $request, int $ if ($request->user()->cannot('manageShelf', $bar)) { abort(403); } + $bar->load('shelfIngredients'); + $existingBarShelfIngredients = $bar->shelfIngredients->pluck('ingredient_id'); $ingredients = DB::table('ingredients') ->select('id') ->where('bar_id', $bar->id) @@ -271,6 +273,10 @@ public function batchStoreBarIngredients(ShelfIngredientsRequest $request, int $ $models = []; foreach ($ingredients as $dbIngredientId) { + if ($existingBarShelfIngredients->contains($dbIngredientId)) { + continue; + } + $userIngredient = new BarIngredient(); $userIngredient->ingredient_id = $dbIngredientId; $models[] = $userIngredient; From 7a8e9a5078f9c5908e2f4c420a45dae90794b7b3 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 31 Aug 2025 16:00:52 +0200 Subject: [PATCH 11/25] Add Redis wildcard cache clearing --- app/External/Model/Ingredient.php | 2 +- .../Controllers/Public/CocktailController.php | 23 ++++++++++--------- .../Filters/PublicCocktailQueryFilter.php | 16 +++---------- app/Providers/AppServiceProvider.php | 20 ++++++++++++++++ app/Services/CocktailService.php | 3 +++ config/debugbar.php | 2 +- 6 files changed, 40 insertions(+), 26 deletions(-) diff --git a/app/External/Model/Ingredient.php b/app/External/Model/Ingredient.php index c12f64f6..d441994d 100644 --- a/app/External/Model/Ingredient.php +++ b/app/External/Model/Ingredient.php @@ -10,9 +10,9 @@ use Kami\Cocktail\Models\ComplexIngredient; use Kami\Cocktail\External\SupportsDataPack; use Kami\Cocktail\Models\Image as ImageModel; +use Kami\Cocktail\Models\ValueObjects\UnitValueObject; use Kami\Cocktail\Models\Ingredient as IngredientModel; use Kami\Cocktail\Models\IngredientPrice as IngredientPriceModel; -use Kami\Cocktail\Models\ValueObjects\UnitValueObject; readonly class Ingredient implements SupportsDataPack, SupportsDraft2, SupportsCSV { diff --git a/app/Http/Controllers/Public/CocktailController.php b/app/Http/Controllers/Public/CocktailController.php index 99527cc2..a6f9a766 100644 --- a/app/Http/Controllers/Public/CocktailController.php +++ b/app/Http/Controllers/Public/CocktailController.php @@ -41,24 +41,25 @@ public function index(Request $request, int $barId): JsonResource abort(404); } + $queryParams = $request->only(['filter', 'sort', 'page']); + ksort($queryParams); + $cacheKey = 'public_cocktails_index:' . $barId . ':' . sha1(http_build_query($queryParams)); + + if (Cache::has($cacheKey)) { + $cocktails = Cache::get($cacheKey); + + return CocktailResource::collection($cocktails->withQueryString()); + } + try { $cocktailsQuery = new PublicCocktailQueryFilter($bar); } catch (InvalidFilterQuery $e) { abort(400, $e->getMessage()); } - $queryParams = $request->only([ - 'filter', - 'sort', - 'page', - ]); - ksort($queryParams); - $queryString = http_build_query($queryParams); - $cacheKey = 'public_cocktails_index_' . $barId . '_' . sha1($queryString); + $cocktails = $cocktailsQuery->paginate(50); - $cocktails = Cache::remember($cacheKey, 3600, function () use ($cocktailsQuery) { - return $cocktailsQuery->paginate(50); - }); + Cache::put($cacheKey, $cocktails, 3600); return CocktailResource::collection($cocktails->withQueryString()); } diff --git a/app/Http/Filters/PublicCocktailQueryFilter.php b/app/Http/Filters/PublicCocktailQueryFilter.php index a694056f..d0cd5d51 100644 --- a/app/Http/Filters/PublicCocktailQueryFilter.php +++ b/app/Http/Filters/PublicCocktailQueryFilter.php @@ -41,26 +41,16 @@ public function __construct(Bar $bar) 'name', 'created_at', 'abv', - 'total_ingredients', AllowedSort::callback('random', function ($query) { $query->inRandomOrder(); }), ]) - ->allowedIncludes([ - 'glass', - 'method', - 'user', - 'utensils', - 'images', - 'tags', - 'ingredients.ingredient', - ]) ->select('cocktails.*') ->leftJoin('cocktail_ingredients AS ci', 'ci.cocktail_id', '=', 'cocktails.id') ->leftJoin('cocktail_ingredient_substitutes AS cis', 'cis.cocktail_ingredient_id', '=', 'ci.id') - ->leftJoin('bar_ingredients AS bi', function ($query) { - $query->on('bi.ingredient_id', '=', 'ci.ingredient_id'); - }) + // ->leftJoin('bar_ingredients AS bi', function ($query) { + // $query->on('bi.ingredient_id', '=', 'ci.ingredient_id'); + // }) ->where('cocktails.bar_id', $bar->id) ->groupBy('cocktails.id') ->with( diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0c63daa4..7a1575c8 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,9 +3,12 @@ namespace Kami\Cocktail\Providers; use Throwable; +use Illuminate\Support\Str; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Redis; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -32,6 +35,23 @@ public function register() */ public function boot() { + Cache::macro('forgetWildcardRedis', function (string $key) { + try { + $prefix = config('database.redis.options.prefix'); + $redisCache = Redis::connection('cache'); + $foundKeys = $redisCache->keys('*' . $key); + foreach ($foundKeys as $foundKey) { + $keyToDelete = $prefix ? Str::after($foundKey, $prefix) : $foundKey; + Log::debug('Clearing cache key via wildcard', ['key' => $foundKey]); + $redisCache->unlink($keyToDelete); + } + } catch (Throwable $e) { + Log::error('Unable to clear cache with wildcard', ['message' => $e->getMessage()]); + + return; + } + }); + Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) { $event->extendSocialite('authentik', \SocialiteProviders\Authentik\Provider::class); $event->extendSocialite('authelia', \SocialiteProviders\Authelia\Provider::class); diff --git a/app/Services/CocktailService.php b/app/Services/CocktailService.php index 7eed74be..f91f5618 100644 --- a/app/Services/CocktailService.php +++ b/app/Services/CocktailService.php @@ -11,6 +11,7 @@ use Kami\Cocktail\Models\Image; use Illuminate\Support\Collection; use Kami\Cocktail\Models\Cocktail; +use Illuminate\Support\Facades\Cache; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\DatabaseManager; use Kami\Cocktail\Models\CocktailFavorite; @@ -109,6 +110,8 @@ public function createCocktail(CocktailDTO $cocktailDTO): Cocktail // Upsert scout index $cocktail->save(); + Cache::forgetWildcardRedis('public_cocktails_index:' . $cocktail->bar_id . ':*'); + return $cocktail; } diff --git a/config/debugbar.php b/config/debugbar.php index 009c81ce..597fc35d 100644 --- a/config/debugbar.php +++ b/config/debugbar.php @@ -185,7 +185,7 @@ 'logs' => false, // Add the latest log messages 'files' => false, // Show the included files 'config' => false, // Display config settings - 'cache' => false, // Display cache events + 'cache' => true, // Display cache events 'models' => true, // Display models 'livewire' => true, // Display Livewire (when available) 'jobs' => false, // Display dispatched jobs From 2234e747104c2f94ab29835dc8f93a785092df23 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Mon, 1 Sep 2025 18:13:54 +0200 Subject: [PATCH 12/25] Document public cocktails filters --- README.md | 13 +++++++++---- .../Controllers/Public/CocktailController.php | 8 +++++--- app/Http/Filters/PublicCocktailQueryFilter.php | 14 +++++--------- app/Services/CocktailService.php | 6 ++++-- docs/openapi-generated.yaml | 18 ++++++++++++------ 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 9fb3fc20..41f2a0b8 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,12 @@ This repository only contains the API server, if you are looking for easy to use - Data export support in various formats - Support for multiple ingredient prices - Automatic cocktail price calculation based on ingredients -- SSO Support +- Single sign-on (SSO) support +- Recipe recommendations based on your favorites and tags + +## Documentation + +[Documentation is available here.](https://docs.barassistant.app/) ## Container images @@ -63,13 +68,13 @@ We recommend that you always use the latest major release, as it will always be ## Managed instance -Bar Assistant will always be open-source and MIT-licensed, but if you want to support the project or don't want to self-host, you can try officialy managed instance. Visit [barassistant.app](https://barassistant.app/) for more information about our cloud offering. +Bar Assistant will always be open-source and MIT-licensed, but if you want to support the project or don't want to self-host, you can try our official managed instance. Visit [barassistant.app](https://barassistant.app/) for more information about our cloud offering. ![Cloud offering screenshot](/resources/art/art1.png) -## Documentation +## 3rd Party Integrations -[Documentation is available here.](https://bar-assistant.github.io/docs/) +There's an [unofficial Raycast extension](https://www.raycast.com/stupifier/barassistant) maintained by a [community member](https://github.com/zhdenny). ## Contributing diff --git a/app/Http/Controllers/Public/CocktailController.php b/app/Http/Controllers/Public/CocktailController.php index a6f9a766..01d83f8e 100644 --- a/app/Http/Controllers/Public/CocktailController.php +++ b/app/Http/Controllers/Public/CocktailController.php @@ -24,11 +24,13 @@ class CocktailController extends Controller new OAT\Parameter(name: 'filter', in: 'query', description: 'Filter by attributes. You can specify multiple matching filter values by passing a comma separated list of values.', explode: true, style: 'deepObject', schema: new OAT\Schema(type: 'object', properties: [ new OAT\Property(property: 'name', type: 'string', description: 'Filter by cocktail names(s) (fuzzy search)'), new OAT\Property(property: 'ingredient_name', type: 'string', description: 'Filter by cocktail ingredient names(s) (fuzzy search)'), + new OAT\Property(property: 'tag', type: 'string', description: 'Filter by cocktail tag name(s) (fuzzy search)'), + new OAT\Property(property: 'glass', type: 'string', description: 'Filter by cocktail glass type name(s) (fuzzy search)'), + new OAT\Property(property: 'method', type: 'string', description: 'Filter by cocktail method name(s) (fuzzy search)'), new OAT\Property(property: 'bar_shelf', type: 'boolean', description: 'Show only cocktails on the bar shelf'), - new OAT\Property(property: 'abv_min', type: 'number', description: 'Filter by greater than or equal ABV'), - new OAT\Property(property: 'abv_max', type: 'number', description: 'Filter by less than or equal ABV'), + new OAT\Property(property: 'abv', type: 'number', description: 'Filter by greater than or equal ABV. Use >=, >, <=, < operators (e.g., `filter[abv]=>=20` to get cocktails with ABV greater than or equal to 20).'), ])), - new OAT\Parameter(name: 'sort', in: 'query', description: 'Sort by attributes. Available attributes: `name`, `created_at`, `average_rating`, `user_rating`, `abv`, `total_ingredients`, `missing_ingredients`, `missing_bar_ingredients`, `favorited_at`, `random`.', schema: new OAT\Schema(type: 'string')), + new OAT\Parameter(name: 'sort', in: 'query', description: 'Sort by attributes. Available attributes: `name`, `created_at`, `abv`, `random`.', schema: new OAT\Schema(type: 'string')), ], security: [])] #[BAO\SuccessfulResponse(content: [ new BAO\PaginateData(CocktailResource::class), diff --git a/app/Http/Filters/PublicCocktailQueryFilter.php b/app/Http/Filters/PublicCocktailQueryFilter.php index d0cd5d51..3cc11510 100644 --- a/app/Http/Filters/PublicCocktailQueryFilter.php +++ b/app/Http/Filters/PublicCocktailQueryFilter.php @@ -9,6 +9,7 @@ use Spatie\QueryBuilder\AllowedSort; use Spatie\QueryBuilder\QueryBuilder; use Spatie\QueryBuilder\AllowedFilter; +use Spatie\QueryBuilder\Enums\FilterOperator; /** * @extends \Spatie\QueryBuilder\QueryBuilder @@ -24,17 +25,15 @@ public function __construct(Bar $bar) AllowedFilter::exact('id'), AllowedFilter::custom('name', new FilterNameSearch()), AllowedFilter::partial('ingredient_name', 'ingredients.ingredient.name'), + AllowedFilter::partial('tag', 'tags.name'), + AllowedFilter::partial('glass', 'glass.name'), + AllowedFilter::partial('method', 'method.name'), AllowedFilter::callback('bar_shelf', function ($query, $value) use ($bar) { if ($value === true) { $query->whereIn('cocktails.id', $bar->getShelfCocktailsOnce()); } }), - AllowedFilter::callback('abv_min', function ($query, $value) { - $query->where('abv', '>=', $value); - }), - AllowedFilter::callback('abv_max', function ($query, $value) { - $query->where('abv', '<=', $value); - }), + AllowedFilter::operator('abv', FilterOperator::DYNAMIC), ]) ->defaultSort('name') ->allowedSorts([ @@ -48,9 +47,6 @@ public function __construct(Bar $bar) ->select('cocktails.*') ->leftJoin('cocktail_ingredients AS ci', 'ci.cocktail_id', '=', 'cocktails.id') ->leftJoin('cocktail_ingredient_substitutes AS cis', 'cis.cocktail_ingredient_id', '=', 'ci.id') - // ->leftJoin('bar_ingredients AS bi', function ($query) { - // $query->on('bi.ingredient_id', '=', 'ci.ingredient_id'); - // }) ->where('cocktails.bar_id', $bar->id) ->groupBy('cocktails.id') ->with( diff --git a/app/Services/CocktailService.php b/app/Services/CocktailService.php index f91f5618..89999a22 100644 --- a/app/Services/CocktailService.php +++ b/app/Services/CocktailService.php @@ -94,6 +94,8 @@ public function createCocktail(CocktailDTO $cocktailDTO): Cocktail $this->db->commit(); + Cache::forgetWildcardRedis('public_cocktails_index:' . $cocktail->bar_id . ':*'); + if (count($cocktailDTO->images) > 0) { try { $imageModels = Image::findOrFail($cocktailDTO->images); @@ -110,8 +112,6 @@ public function createCocktail(CocktailDTO $cocktailDTO): Cocktail // Upsert scout index $cocktail->save(); - Cache::forgetWildcardRedis('public_cocktails_index:' . $cocktail->bar_id . ':*'); - return $cocktail; } @@ -201,6 +201,8 @@ public function updateCocktail(int $id, CocktailDTO $cocktailDTO): Cocktail $this->db->commit(); + Cache::forgetWildcardRedis('public_cocktails_index:' . $cocktail->bar_id . ':*'); + if (count($cocktailDTO->images) > 0) { try { $imageModels = Image::findOrFail($cocktailDTO->images); diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index 5bda6fca..ed2b450d 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -5923,20 +5923,26 @@ paths: ingredient_name: description: 'Filter by cocktail ingredient names(s) (fuzzy search)' type: string + tag: + description: 'Filter by cocktail tag name(s) (fuzzy search)' + type: string + glass: + description: 'Filter by cocktail glass type name(s) (fuzzy search)' + type: string + method: + description: 'Filter by cocktail method name(s) (fuzzy search)' + type: string bar_shelf: description: 'Show only cocktails on the bar shelf' type: boolean - abv_min: - description: 'Filter by greater than or equal ABV' - type: number - abv_max: - description: 'Filter by less than or equal ABV' + abv: + description: 'Filter by greater than or equal ABV. Use >=, >, <=, < operators (e.g., `filter[abv]=>=20` to get cocktails with ABV greater than or equal to 20).' type: number type: object - name: sort in: query - description: 'Sort by attributes. Available attributes: `name`, `created_at`, `average_rating`, `user_rating`, `abv`, `total_ingredients`, `missing_ingredients`, `missing_bar_ingredients`, `favorited_at`, `random`.' + description: 'Sort by attributes. Available attributes: `name`, `created_at`, `abv`, `random`.' schema: type: string responses: From 54ea0f39191af75ccb5e9706ecae43139d94ef17 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Tue, 23 Sep 2025 20:12:18 +0200 Subject: [PATCH 13/25] Update public cocktail schema --- .../Resources/Public/CocktailResource.php | 6 + app/Models/ValueObjects/AmountValueObject.php | 2 +- composer.lock | 153 +++++++++--------- docs/openapi-generated.yaml | 16 ++ 4 files changed, 101 insertions(+), 76 deletions(-) diff --git a/app/Http/Resources/Public/CocktailResource.php b/app/Http/Resources/Public/CocktailResource.php index e9dc243d..fdb16e84 100644 --- a/app/Http/Resources/Public/CocktailResource.php +++ b/app/Http/Resources/Public/CocktailResource.php @@ -31,7 +31,10 @@ new OAT\Property(property: 'glass', type: 'string', nullable: true, example: 'Highball glass', description: 'Type of glass used for the cocktail'), new OAT\Property(property: 'utensils', type: 'array', items: new OAT\Items(type: 'string'), description: 'Utensils used for preparing the cocktail'), new OAT\Property(property: 'method', type: 'string', nullable: true, example: 'Shaken', description: 'Method of preparation for the cocktail'), + new OAT\Property(property: 'method_dilution_percentage', type: 'number', nullable: true, example: '12', description: 'Dilution percentage associated with the preparation method'), + new OAT\Property(property: 'volume_ml', type: 'number', nullable: true, example: '120', description: 'Total volume of the cocktail in milliliters'), new OAT\Property(property: 'created_at', type: 'string', format: 'date-time', example: '2023-10-01T12:00:00Z', description: 'Date and time when the cocktail was created'), + new OAT\Property(property: 'in_bar_shelf', type: 'boolean', example: true, description: 'Indicates if the cocktail can be made in the current bar'), new OAT\Property(property: 'abv', type: 'number', format: 'float', nullable: true, example: 0.15, description: 'Alcohol by volume percentage of the cocktail'), new OAT\Property(property: 'year', type: 'integer', nullable: true, example: 2023, description: 'Year the cocktail was created or published'), new OAT\Property( @@ -98,7 +101,10 @@ public function toArray($request) 'glass' => $this->glass->name ?? null, 'utensils' => $this->utensils->pluck('name'), 'method' => $this->method->name ?? null, + 'method_dilution_percentage' => $this->method->dilution_percentage ?? null, + 'volume_ml' => $this->getVolume(), 'created_at' => $this->created_at->toAtomString(), + 'in_bar_shelf' => $this->inBarShelf(), 'abv' => $this->abv, 'year' => $this->year, 'ingredients' => $this->ingredients->map(function (CocktailIngredient $cocktailIngredient) { diff --git a/app/Models/ValueObjects/AmountValueObject.php b/app/Models/ValueObjects/AmountValueObject.php index 13efd844..f03b727d 100644 --- a/app/Models/ValueObjects/AmountValueObject.php +++ b/app/Models/ValueObjects/AmountValueObject.php @@ -32,7 +32,7 @@ public function convertTo(UnitValueObject $toUnits): self $convertedMaxAmount = Converter::convertAmount(AmountValue::from($this->amountMax), $fromUnitsEnum, $toUnitsEnum); } - return new self($convertedMinAmount->getValue(), $toUnits, $convertedMaxAmount?->getValue()); + return new self(round($convertedMinAmount->getValue(), 4), $toUnits, $convertedMaxAmount?->getValue()); } public function __toString(): string diff --git a/composer.lock b/composer.lock index 35a2bfc5..0c710d3d 100644 --- a/composer.lock +++ b/composer.lock @@ -1772,20 +1772,20 @@ }, { "name": "laravel/framework", - "version": "v12.26.4", + "version": "v12.28.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09" + "reference": "868c1f2d3dba4df6d21e3a8d818479f094cfd942" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/085a367a32ba86fcfa647bfc796098ae6f795b09", - "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09", + "url": "https://api.github.com/repos/laravel/framework/zipball/868c1f2d3dba4df6d21e3a8d818479f094cfd942", + "reference": "868c1f2d3dba4df6d21e3a8d818479f094cfd942", "shasum": "" }, "require": { - "brick/math": "^0.11|^0.12|^0.13", + "brick/math": "^0.11|^0.12|^0.13|^0.14", "composer-runtime-api": "^2.2", "doctrine/inflector": "^2.0.5", "dragonmantank/cron-expression": "^3.4", @@ -1859,6 +1859,7 @@ "illuminate/filesystem": "self.version", "illuminate/hashing": "self.version", "illuminate/http": "self.version", + "illuminate/json-schema": "self.version", "illuminate/log": "self.version", "illuminate/macroable": "self.version", "illuminate/mail": "self.version", @@ -1891,7 +1892,8 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^10.6.3", + "opis/json-schema": "^2.4.1", + "orchestra/testbench-core": "^10.6.5", "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", @@ -1985,20 +1987,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-08-29T14:15:53+00:00" + "time": "2025-09-04T14:58:12+00:00" }, { "name": "laravel/horizon", - "version": "v5.33.4", + "version": "v5.33.5", "source": { "type": "git", "url": "https://github.com/laravel/horizon.git", - "reference": "678362049ce5b9ce96673ac0282bbfda3279eca9" + "reference": "ef1c74b8134432eddabbd512e6e61a2e84a13d7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/horizon/zipball/678362049ce5b9ce96673ac0282bbfda3279eca9", - "reference": "678362049ce5b9ce96673ac0282bbfda3279eca9", + "url": "https://api.github.com/repos/laravel/horizon/zipball/ef1c74b8134432eddabbd512e6e61a2e84a13d7a", + "reference": "ef1c74b8134432eddabbd512e6e61a2e84a13d7a", "shasum": "" }, "require": { @@ -2063,9 +2065,9 @@ ], "support": { "issues": "https://github.com/laravel/horizon/issues", - "source": "https://github.com/laravel/horizon/tree/v5.33.4" + "source": "https://github.com/laravel/horizon/tree/v5.33.5" }, - "time": "2025-08-25T13:31:24+00:00" + "time": "2025-08-31T23:36:14+00:00" }, { "name": "laravel/prompts", @@ -2595,16 +2597,16 @@ }, { "name": "league/csv", - "version": "9.24.1", + "version": "9.25.0", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8" + "reference": "f856f532866369fb1debe4e7c5a1db185f40ef86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/e0221a3f16aa2a823047d59fab5809d552e29bc8", - "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/f856f532866369fb1debe4e7c5a1db185f40ef86", + "reference": "f856f532866369fb1debe4e7c5a1db185f40ef86", "shasum": "" }, "require": { @@ -2620,7 +2622,7 @@ "phpstan/phpstan-deprecation-rules": "^1.2.1", "phpstan/phpstan-phpunit": "^1.4.2", "phpstan/phpstan-strict-rules": "^1.6.2", - "phpunit/phpunit": "^10.5.16 || ^11.5.22", + "phpunit/phpunit": "^10.5.16 || ^11.5.22 || ^12.3.6", "symfony/var-dumper": "^6.4.8 || ^7.3.0" }, "suggest": { @@ -2682,7 +2684,7 @@ "type": "github" } ], - "time": "2025-06-25T14:53:51+00:00" + "time": "2025-09-11T08:29:08+00:00" }, { "name": "league/flysystem", @@ -3191,16 +3193,16 @@ }, { "name": "meilisearch/meilisearch-php", - "version": "v1.15.0", + "version": "v1.16.0", "source": { "type": "git", "url": "https://github.com/meilisearch/meilisearch-php.git", - "reference": "94930b9e4b8a6c1ad841eed1395a58a73d0db313" + "reference": "04f7e5454dcd21b968771ec7c05a88ef852f501c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/meilisearch/meilisearch-php/zipball/94930b9e4b8a6c1ad841eed1395a58a73d0db313", - "reference": "94930b9e4b8a6c1ad841eed1395a58a73d0db313", + "url": "https://api.github.com/repos/meilisearch/meilisearch-php/zipball/04f7e5454dcd21b968771ec7c05a88ef852f501c", + "reference": "04f7e5454dcd21b968771ec7c05a88ef852f501c", "shasum": "" }, "require": { @@ -3210,18 +3212,19 @@ "psr/http-client": "^1.0" }, "require-dev": { - "guzzlehttp/guzzle": "^7.8.1", "http-interop/http-factory-guzzle": "^1.2.0", "php-cs-fixer/shim": "^3.59.3", "phpstan/phpstan": "^2.0", "phpstan/phpstan-deprecation-rules": "^2.0", "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.5 || ^10.5" + "phpunit/phpunit": "^9.5 || ^10.5", + "symfony/http-client": "^5.4|^6.0|^7.0" }, "suggest": { "guzzlehttp/guzzle": "Use Guzzle ^7 as HTTP client", - "http-interop/http-factory-guzzle": "Factory for guzzlehttp/guzzle" + "http-interop/http-factory-guzzle": "Factory for guzzlehttp/guzzle", + "symfony/http-client": "Use Symfony Http client" }, "type": "library", "autoload": { @@ -3251,9 +3254,9 @@ ], "support": { "issues": "https://github.com/meilisearch/meilisearch-php/issues", - "source": "https://github.com/meilisearch/meilisearch-php/tree/v1.15.0" + "source": "https://github.com/meilisearch/meilisearch-php/tree/v1.16.0" }, - "time": "2025-06-10T04:33:15+00:00" + "time": "2025-09-10T08:50:58+00:00" }, { "name": "moneyphp/money", @@ -3450,16 +3453,16 @@ }, { "name": "nesbot/carbon", - "version": "3.10.2", + "version": "3.10.3", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" + "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", "shasum": "" }, "require": { @@ -3477,13 +3480,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.75.0", + "friendsofphp/php-cs-fixer": "^v3.87.1", "kylekatarnls/multi-tester": "^2.5.3", "phpmd/phpmd": "^2.15.0", "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^2.1.17", - "phpunit/phpunit": "^10.5.46", - "squizlabs/php_codesniffer": "^3.13.0" + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4" }, "bin": [ "bin/carbon" @@ -3551,7 +3554,7 @@ "type": "tidelift" } ], - "time": "2025-08-02T09:36:06+00:00" + "time": "2025-09-06T13:39:36+00:00" }, { "name": "nette/schema", @@ -4968,20 +4971,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.0", + "version": "4.9.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0" + "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0", - "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440", + "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -5040,22 +5043,22 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.0" + "source": "https://github.com/ramsey/uuid/tree/4.9.1" }, - "time": "2025-06-25T14:20:11+00:00" + "time": "2025-09-04T20:59:21+00:00" }, { "name": "sentry/sentry", - "version": "4.15.1", + "version": "4.15.2", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "0d09baf3700869ec4b723c95eb466de56c3d74b6" + "reference": "61a2d918e8424b6de4a2e265c15133a00c17db51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/0d09baf3700869ec4b723c95eb466de56c3d74b6", - "reference": "0d09baf3700869ec4b723c95eb466de56c3d74b6", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/61a2d918e8424b6de4a2e265c15133a00c17db51", + "reference": "61a2d918e8424b6de4a2e265c15133a00c17db51", "shasum": "" }, "require": { @@ -5119,7 +5122,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.15.1" + "source": "https://github.com/getsentry/sentry-php/tree/4.15.2" }, "funding": [ { @@ -5131,27 +5134,27 @@ "type": "custom" } ], - "time": "2025-08-28T15:45:14+00:00" + "time": "2025-09-03T07:23:48+00:00" }, { "name": "sentry/sentry-laravel", - "version": "4.15.1", + "version": "4.16.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-laravel.git", - "reference": "7e0675e8e06d1ec5cb623792892920000a3aedb5" + "reference": "b33b2e487b02db02d92988228f142d7fa2be2bfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/7e0675e8e06d1ec5cb623792892920000a3aedb5", - "reference": "7e0675e8e06d1ec5cb623792892920000a3aedb5", + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/b33b2e487b02db02d92988228f142d7fa2be2bfa", + "reference": "b33b2e487b02db02d92988228f142d7fa2be2bfa", "shasum": "" }, "require": { "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0", "nyholm/psr7": "^1.0", "php": "^7.2 | ^8.0", - "sentry/sentry": "^4.14.1", + "sentry/sentry": "^4.15.2", "symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0" }, "require-dev": { @@ -5208,7 +5211,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-laravel/issues", - "source": "https://github.com/getsentry/sentry-laravel/tree/4.15.1" + "source": "https://github.com/getsentry/sentry-laravel/tree/4.16.0" }, "funding": [ { @@ -5220,7 +5223,7 @@ "type": "custom" } ], - "time": "2025-06-24T12:39:03+00:00" + "time": "2025-09-10T16:38:18+00:00" }, { "name": "socialiteproviders/authelia", @@ -10074,16 +10077,16 @@ }, { "name": "larastan/larastan", - "version": "v3.6.1", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "3c223047e374befd1b64959784685d6ecccf66aa" + "reference": "2e653fd19585a825e283b42f38378b21ae481cc7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/3c223047e374befd1b64959784685d6ecccf66aa", - "reference": "3c223047e374befd1b64959784685d6ecccf66aa", + "url": "https://api.github.com/repos/larastan/larastan/zipball/2e653fd19585a825e283b42f38378b21ae481cc7", + "reference": "2e653fd19585a825e283b42f38378b21ae481cc7", "shasum": "" }, "require": { @@ -10097,7 +10100,7 @@ "illuminate/pipeline": "^11.44.2 || ^12.4.1", "illuminate/support": "^11.44.2 || ^12.4.1", "php": "^8.2", - "phpstan/phpstan": "^2.1.11" + "phpstan/phpstan": "^2.1.23" }, "require-dev": { "doctrine/coding-standard": "^13", @@ -10151,7 +10154,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v3.6.1" + "source": "https://github.com/larastan/larastan/tree/v3.7.1" }, "funding": [ { @@ -10159,7 +10162,7 @@ "type": "github" } ], - "time": "2025-08-25T07:24:56+00:00" + "time": "2025-09-10T19:42:11+00:00" }, { "name": "laravel/pint", @@ -10665,16 +10668,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.22", + "version": "2.1.25", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4" + "reference": "4087d28bd252895874e174d65e26b2c202ed893a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4", - "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4087d28bd252895874e174d65e26b2c202ed893a", + "reference": "4087d28bd252895874e174d65e26b2c202ed893a", "shasum": "" }, "require": { @@ -10719,7 +10722,7 @@ "type": "github" } ], - "time": "2025-08-04T19:17:37+00:00" + "time": "2025-09-12T14:26:42+00:00" }, { "name": "phpunit/php-code-coverage", @@ -11058,16 +11061,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.35", + "version": "11.5.38", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "d341ee94ee5007b286fc7907b383aae6b5b3cc91" + "reference": "5bd0e4f64a2261b7ade7054c51547beaf2d99e43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d341ee94ee5007b286fc7907b383aae6b5b3cc91", - "reference": "d341ee94ee5007b286fc7907b383aae6b5b3cc91", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5bd0e4f64a2261b7ade7054c51547beaf2d99e43", + "reference": "5bd0e4f64a2261b7ade7054c51547beaf2d99e43", "shasum": "" }, "require": { @@ -11139,7 +11142,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.35" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.38" }, "funding": [ { @@ -11163,7 +11166,7 @@ "type": "tidelift" } ], - "time": "2025-08-28T05:13:54+00:00" + "time": "2025-09-11T10:34:07+00:00" }, { "name": "sebastian/cli-parser", diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index ed2b450d..bfa91552 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -10106,11 +10106,27 @@ components: - string - 'null' example: Shaken + method_dilution_percentage: + description: 'Dilution percentage associated with the preparation method' + type: + - number + - 'null' + example: '12' + volume_ml: + description: 'Total volume of the cocktail in milliliters' + type: + - number + - 'null' + example: '120' created_at: description: 'Date and time when the cocktail was created' type: string format: date-time example: '2023-10-01T12:00:00Z' + in_bar_shelf: + description: 'Indicates if the cocktail can be made in the current bar' + type: boolean + example: true abv: description: 'Alcohol by volume percentage of the cocktail' type: From 995a927f53ac381bec88813da046a5ae1000fdc2 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Tue, 23 Sep 2025 20:12:26 +0200 Subject: [PATCH 14/25] Add missing check --- app/External/Model/Ingredient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/External/Model/Ingredient.php b/app/External/Model/Ingredient.php index d441994d..a2709939 100644 --- a/app/External/Model/Ingredient.php +++ b/app/External/Model/Ingredient.php @@ -58,7 +58,7 @@ public static function fromModel(IngredientModel $model, bool $useFileURI = fals })->toArray(); $defaultIngredientUnits = $model->getDefaultUnits(); - if ($model->getDefaultUnits()?->isConvertable()) { + if ($model->getDefaultUnits()?->isConvertable() && $toUnits) { $defaultIngredientUnits = new UnitValueObject($toUnits->value); } From 49d548a7a31f5df3e756d65877fe17391afa9e9c Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 28 Sep 2025 11:11:07 +0200 Subject: [PATCH 15/25] Improve error handling --- app/Http/Controllers/SubscriptionController.php | 7 ++++++- app/Http/Resources/Public/CocktailResource.php | 1 + app/Models/Menu.php | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/SubscriptionController.php b/app/Http/Controllers/SubscriptionController.php index 366a2c19..3a6f0b70 100644 --- a/app/Http/Controllers/SubscriptionController.php +++ b/app/Http/Controllers/SubscriptionController.php @@ -8,6 +8,7 @@ use Illuminate\Http\Request; use OpenApi\Attributes as OAT; use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\Log; use Kami\Cocktail\OpenAPI as BAO; use Illuminate\Support\Facades\Mail; use Kami\Cocktail\Mail\SubscriptionChanged; @@ -30,7 +31,11 @@ public function subscription(Request $request): UserSubscriptionResource $customer = $user->customer; if (!$customer) { - $customer = $user->createAsCustomer(); + try { + $customer = $user->createAsCustomer(); + } catch (Throwable $e) { + Log::warning($e->getMessage()); + } } return new UserSubscriptionResource($user); diff --git a/app/Http/Resources/Public/CocktailResource.php b/app/Http/Resources/Public/CocktailResource.php index fdb16e84..9ae0c781 100644 --- a/app/Http/Resources/Public/CocktailResource.php +++ b/app/Http/Resources/Public/CocktailResource.php @@ -90,6 +90,7 @@ public function toArray($request) 'description' => e($this->description), 'source' => $this->source, 'public_id' => $this->public_id, + 'bar_id' => $this->bar_id, 'public_at' => $this->public_at?->toAtomString() ?? null, 'images' => ImageResource::collection($this->images), 'tags' => $this->when( diff --git a/app/Models/Menu.php b/app/Models/Menu.php index e57bc7f9..9b9fb5b4 100644 --- a/app/Models/Menu.php +++ b/app/Models/Menu.php @@ -55,8 +55,8 @@ public function bar(): BelongsTo */ public function getMenuItems(): Collection { - $cocktails = $this->menuCocktails->map(fn (MenuCocktail $menuCocktail) => MenuItem::fromMenuCocktail($menuCocktail)); - $ingredients = $this->menuIngredients->map(fn (MenuIngredient $menuIngredient) => MenuItem::fromMenuIngredient($menuIngredient)); + $cocktails = $this->menuCocktails->map(fn (MenuCocktail $menuCocktail) => MenuItem::fromMenuCocktail($menuCocktail))->values(); + $ingredients = $this->menuIngredients->map(fn (MenuIngredient $menuIngredient) => MenuItem::fromMenuIngredient($menuIngredient))->values(); return $cocktails->merge($ingredients)->values(); } From 9c45962670d3a3083c5b20861ffff428c7968c09 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 28 Sep 2025 17:03:40 +0200 Subject: [PATCH 16/25] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21cf46c6..4e0ee28e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v5.8.1 +## Fixes +- Fixed missing API ability on `import/cocktail` endpoint + # v5.8.0 ## New - Added `bars/{id}/sync-datapack` endpoint From f421281ffa496b323cc1953be5c87c935c59c85f Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 5 Oct 2025 14:31:25 +0200 Subject: [PATCH 17/25] Escape html --- resources/views/md_recipe_template.blade.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/views/md_recipe_template.blade.php b/resources/views/md_recipe_template.blade.php index cc3a5d19..35b0eed4 100644 --- a/resources/views/md_recipe_template.blade.php +++ b/resources/views/md_recipe_template.blade.php @@ -1,8 +1,8 @@ -# {!! $cocktail->name !!} +# {{ $cocktail->name }} @if ($cocktail->source) [Recipe source]({{ $cocktail->source }}) @endif -{!! $cocktail->description !!} +{{ $cocktail->description }} @foreach ($cocktail->images as $image) ![{{ $image->copyright }}]({{ $image->uri }}) @@ -10,18 +10,18 @@ ## Ingredients @foreach ($cocktail->ingredients as $ci) -- {!! (new \Kami\Cocktail\Models\ValueObjects\CocktailIngredientFormatter($ci->amount, $ci->ingredient->name, $ci->optional))->format() !!}{!! $ci->note ? ' - ' . $ci->note : '' !!} +- {{ (new \Kami\Cocktail\Models\ValueObjects\CocktailIngredientFormatter($ci->amount, $ci->ingredient->name, $ci->optional))->format() }}{{ $ci->note ? ' - ' . $ci->note : '' }} @foreach ($ci->substitutes as $sub) - - or {!! (new \Kami\Cocktail\Models\ValueObjects\CocktailIngredientFormatter($sub->amount, $sub->ingredient->name))->format() !!} + - or {{ (new \Kami\Cocktail\Models\ValueObjects\CocktailIngredientFormatter($sub->amount, $sub->ingredient->name))->format() }} @endforeach @endforeach ## Instructions -{!! $cocktail->instructions !!} +{{ $cocktail->instructions }} @if ($cocktail->garnish) ### Garnish -{!! $cocktail->garnish !!} +{{ $cocktail->garnish }} @endif --- From 8509c3623ea984efba49738d061708fe7b59f97b Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 11 Oct 2025 10:23:30 +0200 Subject: [PATCH 18/25] Update schema --- app/Http/Controllers/BarController.php | 7 +- app/Http/Controllers/Public/BarController.php | 8 +- .../Controllers/Public/CocktailController.php | 33 +- .../Controllers/ShoppingListController.php | 8 +- app/Http/Controllers/StatsController.php | 9 +- app/Http/Resources/Public/BarResource.php | 4 +- .../Resources/Public/CocktailResource.php | 1 - app/Models/Bar.php | 9 + composer.lock | 452 +++++++++++------- config/auth.php | 3 - docs/openapi-generated.yaml | 25 +- 11 files changed, 336 insertions(+), 223 deletions(-) diff --git a/app/Http/Controllers/BarController.php b/app/Http/Controllers/BarController.php index b0704c8d..b1a553cb 100644 --- a/app/Http/Controllers/BarController.php +++ b/app/Http/Controllers/BarController.php @@ -23,6 +23,7 @@ use Illuminate\Http\Resources\Json\JsonResource; use Kami\Cocktail\Http\Resources\BarMembershipResource; use Kami\Cocktail\OpenAPI\Schemas\BarRequest as SchemasBarRequest; +use Throwable; class BarController extends Controller { @@ -87,7 +88,7 @@ public function show(Request $request, int $id): JsonResource public function store(BarRequest $request): JsonResponse { if ($request->user()->cannot('create', Bar::class)) { - abort(403, 'You can not create anymore bars'); + abort(403, 'You can not create any more bars.'); } Cache::forget('metrics_bass_total_bars'); @@ -106,7 +107,7 @@ public function store(BarRequest $request): JsonResponse try { $imageModels = Image::findOrFail($barRequest->images); $bar->attachImages($imageModels); - } catch (\Throwable $e) { + } catch (Throwable $e) { abort(500, $e->getMessage()); } } @@ -167,7 +168,7 @@ public function update(int $id, BarRequest $request): JsonResource try { $imageModels = Image::findOrFail($barRequest->images); $bar->attachImages($imageModels); - } catch (\Throwable $e) { + } catch (Throwable $e) { abort(500, $e->getMessage()); } } diff --git a/app/Http/Controllers/Public/BarController.php b/app/Http/Controllers/Public/BarController.php index a4fe3169..b70bcc12 100644 --- a/app/Http/Controllers/Public/BarController.php +++ b/app/Http/Controllers/Public/BarController.php @@ -12,17 +12,17 @@ class BarController extends Controller { - #[OAT\Get(path: '/public/{barId}', tags: ['Public'], operationId: 'showPublicBar', description: 'Show public information about a single bar. To access this endpoint the bar must be marked as public.', summary: 'Show bar', parameters: [ - new OAT\Parameter(name: 'barId', in: 'path', required: true, description: 'Database id of bar', schema: new OAT\Schema(type: 'number')), + #[OAT\Get(path: '/public/{slugOrId}', tags: ['Public'], operationId: 'showPublicBar', description: 'Show public information about a single bar. To access this endpoint the bar must be marked as public.', summary: 'Show bar', parameters: [ + new OAT\Parameter(name: 'slugOrId', in: 'path', required: true, description: 'Database id of bar', schema: new OAT\Schema(type: 'string')), new BAO\Parameters\PageParameter(), ], security: [])] #[BAO\SuccessfulResponse(content: [ new BAO\WrapObjectWithData(BarResource::class), ])] #[BAO\NotFoundResponse] - public function show(int $barId): BarResource + public function show(string $slugOrId): BarResource { - $bar = Bar::findOrFail($barId); + $bar = Bar::where('slug', $slugOrId)->orWhere('id', $slugOrId)->firstOrFail(); if (!$bar->is_public) { abort(404); } diff --git a/app/Http/Controllers/Public/CocktailController.php b/app/Http/Controllers/Public/CocktailController.php index 01d83f8e..4b929c88 100644 --- a/app/Http/Controllers/Public/CocktailController.php +++ b/app/Http/Controllers/Public/CocktailController.php @@ -18,8 +18,8 @@ class CocktailController extends Controller { - #[OAT\Get(path: '/public/{barId}/cocktails', tags: ['Public'], operationId: 'listPublicBarCocktails', description: 'List and filter bar cocktails. To access this endpoint the bar must be marked as public.', summary: 'List cocktails', parameters: [ - new OAT\Parameter(name: 'barId', in: 'path', required: true, description: 'Database id of bar', schema: new OAT\Schema(type: 'number')), + #[OAT\Get(path: '/public/{slugOrId}/cocktails', tags: ['Public'], operationId: 'listPublicBarCocktails', description: 'List and filter bar cocktails. To access this endpoint the bar must be marked as public.', summary: 'List cocktails', parameters: [ + new OAT\Parameter(name: 'slugOrId', in: 'path', required: true, description: 'Database id or slug of bar', schema: new OAT\Schema(type: 'string')), new BAO\Parameters\PageParameter(), new OAT\Parameter(name: 'filter', in: 'query', description: 'Filter by attributes. You can specify multiple matching filter values by passing a comma separated list of values.', explode: true, style: 'deepObject', schema: new OAT\Schema(type: 'object', properties: [ new OAT\Property(property: 'name', type: 'string', description: 'Filter by cocktail names(s) (fuzzy search)'), @@ -36,16 +36,16 @@ class CocktailController extends Controller new BAO\PaginateData(CocktailResource::class), ])] #[BAO\NotFoundResponse] - public function index(Request $request, int $barId): JsonResource + public function index(Request $request, string $slugOrId): JsonResource { - $bar = Bar::findOrFail($barId); + $bar = Bar::where('slug', $slugOrId)->orWhere('id', $slugOrId)->firstOrFail(); if (!$bar->is_public) { abort(404); } $queryParams = $request->only(['filter', 'sort', 'page']); ksort($queryParams); - $cacheKey = 'public_cocktails_index:' . $barId . ':' . sha1(http_build_query($queryParams)); + $cacheKey = 'public_cocktails_index:' . $bar->id . ':' . sha1(http_build_query($queryParams)); if (Cache::has($cacheKey)) { $cocktails = Cache::get($cacheKey); @@ -66,31 +66,26 @@ public function index(Request $request, int $barId): JsonResource return CocktailResource::collection($cocktails->withQueryString()); } - #[OAT\Get(path: '/public/{barId}/cocktails/{slugOrPublicId}', tags: ['Public'], operationId: 'showPublicBarCocktail', description: 'Show public information about cocktail. If valid public ID is provided it will used, if not it will use cocktail slug.', summary: 'Show cocktail', parameters: [ - new OAT\Parameter(name: 'barId', in: 'path', required: true, description: 'Database id of bar', schema: new OAT\Schema(type: 'number')), + #[OAT\Get(path: '/public/{slugOrId}/cocktails/{slugOrPublicId}', tags: ['Public'], operationId: 'showPublicBarCocktail', description: 'Show public information about cocktail. If valid public ID is provided it will used, if not it will use cocktail slug.', summary: 'Show cocktail', parameters: [ + new OAT\Parameter(name: 'slugOrId', in: 'path', required: true, description: 'Database id of bar', schema: new OAT\Schema(type: 'string')), new OAT\Parameter(name: 'slugOrPublicId', in: 'path', required: true, description: 'Cocktail slug or public id (ULID)', schema: new OAT\Schema(type: 'string')), ], security: [])] #[BAO\SuccessfulResponse(content: [ new BAO\WrapObjectWithData(CocktailResource::class), ])] #[BAO\NotFoundResponse] - public function show(int $barId, string $slugOrPublicId): CocktailResource + public function show(string $barId, string $slugOrPublicId): CocktailResource { - $cocktail = Cocktail::where('bar_id', $barId) - ->where('public_id', $slugOrPublicId) - ->orWhere('slug', $slugOrPublicId) - ->with('ingredients.ingredient', 'ingredients.substitutes.ingredient', 'images', 'tags', 'utensils') - ->firstOrFail(); - - if ($cocktail->public_id === $slugOrPublicId) { - return new CocktailResource($cocktail); - } - - $bar = Bar::findOrFail($barId); + $bar = Bar::where('slug', $barId)->orWhere('id', $barId)->firstOrFail(); if (!$bar->is_public) { abort(404); } + $cocktail = Cocktail::where('public_id', $slugOrPublicId) + ->orWhere('slug', $slugOrPublicId) + ->with('ingredients.ingredient', 'ingredients.substitutes.ingredient', 'images', 'tags', 'utensils') + ->firstOrFail(); + return new CocktailResource($cocktail); } } diff --git a/app/Http/Controllers/ShoppingListController.php b/app/Http/Controllers/ShoppingListController.php index a8fc6198..53c6d316 100644 --- a/app/Http/Controllers/ShoppingListController.php +++ b/app/Http/Controllers/ShoppingListController.php @@ -30,7 +30,7 @@ class ShoppingListController extends Controller public function index(Request $request, int $id): JsonResource { $user = User::findOrFail($id); - if ($request->user()->id !== $user->id && $request->user()->cannot('show', $user)) { + if ($request->user()->id !== $user->id || $request->user()->cannot('show', $user)) { abort(403); } @@ -54,7 +54,7 @@ public function index(Request $request, int $id): JsonResource public function batchStore(IngredientsBatchRequest $request, int $id): Response { $user = User::findOrFail($id); - if ($request->user()->id !== $user->id && $request->user()->cannot('show', $user)) { + if ($request->user()->id !== $user->id || $request->user()->cannot('show', $user)) { abort(403); } @@ -111,7 +111,7 @@ public function batchStore(IngredientsBatchRequest $request, int $id): Response public function batchDelete(IngredientsBatchRequest $request, int $id): Response { $user = User::findOrFail($id); - if ($request->user()->id !== $user->id && $request->user()->cannot('show', $user)) { + if ($request->user()->id !== $user->id || $request->user()->cannot('show', $user)) { abort(403); } @@ -150,7 +150,7 @@ public function batchDelete(IngredientsBatchRequest $request, int $id): Response public function share(Request $request, int $id): JsonResponse { $user = User::findOrFail($id); - if ($request->user()->id !== $user->id && $request->user()->cannot('show', $user)) { + if ($request->user()->id !== $user->id || $request->user()->cannot('show', $user)) { abort(403); } diff --git a/app/Http/Controllers/StatsController.php b/app/Http/Controllers/StatsController.php index 1e13f569..7b28a2a3 100644 --- a/app/Http/Controllers/StatsController.php +++ b/app/Http/Controllers/StatsController.php @@ -31,7 +31,14 @@ class StatsController extends Controller public function index(CocktailService $cocktailRepo, Request $request, int $id): JsonResponse { $bar = Bar::findOrFail($id); - $barMembership = $request->user()->getBarMembership($bar->id)->load('userIngredients'); + $barMembership = $request->user()->getBarMembership($bar->id); + + if ($barMembership === null) { + abort(403); + } + + $barMembership->load('userIngredients'); + $limit = 5; $stats = []; diff --git a/app/Http/Resources/Public/BarResource.php b/app/Http/Resources/Public/BarResource.php index 8d81da97..c8b38ce6 100644 --- a/app/Http/Resources/Public/BarResource.php +++ b/app/Http/Resources/Public/BarResource.php @@ -20,8 +20,9 @@ new OAT\Property(property: 'subtitle', type: 'string', nullable: true, example: 'A short subtitle of a bar', description: 'Optional short quip about the bar'), new OAT\Property(property: 'description', type: 'string', nullable: true, example: 'Bar description', description: 'Description of the bar'), new OAT\Property(property: 'images', type: 'array', items: new OAT\Items(type: ImageResource::class), description: 'Images associated with the bar'), + new OAT\Property(property: 'is_menu_enabled', type: 'boolean', example: true, description: 'Whether the bar has enabled its menu for public viewing'), ], - required: ['id', 'slug', 'name', 'subtitle', 'description', 'images'], + required: ['id', 'slug', 'name', 'subtitle', 'description', 'images', 'is_menu_enabled'], )] class BarResource extends JsonResource { @@ -40,6 +41,7 @@ public function toArray($request) 'subtitle' => $this->subtitle, 'description' => $this->description, 'images' => ImageResource::collection($this->images), + 'is_menu_enabled' => $this->menu?->is_enabled ?? false, ]; } } diff --git a/app/Http/Resources/Public/CocktailResource.php b/app/Http/Resources/Public/CocktailResource.php index 9ae0c781..fdb16e84 100644 --- a/app/Http/Resources/Public/CocktailResource.php +++ b/app/Http/Resources/Public/CocktailResource.php @@ -90,7 +90,6 @@ public function toArray($request) 'description' => e($this->description), 'source' => $this->source, 'public_id' => $this->public_id, - 'bar_id' => $this->bar_id, 'public_at' => $this->public_at?->toAtomString() ?? null, 'images' => ImageResource::collection($this->images), 'tags' => $this->when( diff --git a/app/Models/Bar.php b/app/Models/Bar.php index 56138263..d90839b0 100644 --- a/app/Models/Bar.php +++ b/app/Models/Bar.php @@ -18,6 +18,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Eloquent\Relations\HasOne; class Bar extends Model implements UploadableInterface { @@ -133,6 +134,14 @@ public function exports(): HasMany return $this->hasMany(Export::class); } + /** + * @return HasOne + */ + public function menu(): HasOne + { + return $this->hasOne(Menu::class); + } + public function owner(): User { return $this->createdUser; diff --git a/composer.lock b/composer.lock index 0c710d3d..ccd670b9 100644 --- a/composer.lock +++ b/composer.lock @@ -1772,16 +1772,16 @@ }, { "name": "laravel/framework", - "version": "v12.28.1", + "version": "v12.32.5", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "868c1f2d3dba4df6d21e3a8d818479f094cfd942" + "reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/868c1f2d3dba4df6d21e3a8d818479f094cfd942", - "reference": "868c1f2d3dba4df6d21e3a8d818479f094cfd942", + "url": "https://api.github.com/repos/laravel/framework/zipball/77b2740391cd2a825ba59d6fada45e9b8b9bcc5a", + "reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a", "shasum": "" }, "require": { @@ -1918,7 +1918,7 @@ "ext-pdo": "Required to use all database features.", "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", - "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "fakerphp/faker": "Required to generate fake data using the fake() helper (^1.23).", "filp/whoops": "Required for friendly error pages in development (^2.14.3).", "laravel/tinker": "Required to use the tinker console command (^2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", @@ -1987,20 +1987,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-09-04T14:58:12+00:00" + "time": "2025-09-30T17:39:22+00:00" }, { "name": "laravel/horizon", - "version": "v5.33.5", + "version": "v5.34.0", "source": { "type": "git", "url": "https://github.com/laravel/horizon.git", - "reference": "ef1c74b8134432eddabbd512e6e61a2e84a13d7a" + "reference": "c110ff6ed494b57beb6b4102a92bb4bf896bb774" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/horizon/zipball/ef1c74b8134432eddabbd512e6e61a2e84a13d7a", - "reference": "ef1c74b8134432eddabbd512e6e61a2e84a13d7a", + "url": "https://api.github.com/repos/laravel/horizon/zipball/c110ff6ed494b57beb6b4102a92bb4bf896bb774", + "reference": "c110ff6ed494b57beb6b4102a92bb4bf896bb774", "shasum": "" }, "require": { @@ -2065,22 +2065,22 @@ ], "support": { "issues": "https://github.com/laravel/horizon/issues", - "source": "https://github.com/laravel/horizon/tree/v5.33.5" + "source": "https://github.com/laravel/horizon/tree/v5.34.0" }, - "time": "2025-08-31T23:36:14+00:00" + "time": "2025-09-12T15:15:45+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.6", + "version": "v0.3.7", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "86a8b692e8661d0fb308cec64f3d176821323077" + "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/86a8b692e8661d0fb308cec64f3d176821323077", - "reference": "86a8b692e8661d0fb308cec64f3d176821323077", + "url": "https://api.github.com/repos/laravel/prompts/zipball/a1891d362714bc40c8d23b0b1d7090f022ea27cc", + "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc", "shasum": "" }, "require": { @@ -2097,8 +2097,8 @@ "illuminate/collections": "^10.0|^11.0|^12.0", "mockery/mockery": "^1.5", "pestphp/pest": "^2.3|^3.4", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-mockery": "^1.1" + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" }, "suggest": { "ext-pcntl": "Required for the spinner to be animated." @@ -2124,9 +2124,9 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.6" + "source": "https://github.com/laravel/prompts/tree/v0.3.7" }, - "time": "2025-07-07T14:17:42+00:00" + "time": "2025-09-19T13:47:56+00:00" }, { "name": "laravel/sanctum", @@ -2275,16 +2275,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v2.0.4", + "version": "v2.0.5", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" + "reference": "3832547db6e0e2f8bb03d4093857b378c66eceed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", - "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3832547db6e0e2f8bb03d4093857b378c66eceed", + "reference": "3832547db6e0e2f8bb03d4093857b378c66eceed", "shasum": "" }, "require": { @@ -2332,7 +2332,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2025-03-19T13:51:03+00:00" + "time": "2025-09-22T17:29:40+00:00" }, { "name": "laravel/socialite", @@ -2597,16 +2597,16 @@ }, { "name": "league/csv", - "version": "9.25.0", + "version": "9.26.0", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "f856f532866369fb1debe4e7c5a1db185f40ef86" + "reference": "7fce732754d043f3938899e5183e2d0f3d31b571" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/f856f532866369fb1debe4e7c5a1db185f40ef86", - "reference": "f856f532866369fb1debe4e7c5a1db185f40ef86", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/7fce732754d043f3938899e5183e2d0f3d31b571", + "reference": "7fce732754d043f3938899e5183e2d0f3d31b571", "shasum": "" }, "require": { @@ -2684,7 +2684,7 @@ "type": "github" } ], - "time": "2025-09-11T08:29:08+00:00" + "time": "2025-10-01T11:24:54+00:00" }, { "name": "league/flysystem", @@ -3193,23 +3193,24 @@ }, { "name": "meilisearch/meilisearch-php", - "version": "v1.16.0", + "version": "v1.16.1", "source": { "type": "git", "url": "https://github.com/meilisearch/meilisearch-php.git", - "reference": "04f7e5454dcd21b968771ec7c05a88ef852f501c" + "reference": "f9f63e0e7d12ffaae54f7317fa8f4f4dfa8ae7b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/meilisearch/meilisearch-php/zipball/04f7e5454dcd21b968771ec7c05a88ef852f501c", - "reference": "04f7e5454dcd21b968771ec7c05a88ef852f501c", + "url": "https://api.github.com/repos/meilisearch/meilisearch-php/zipball/f9f63e0e7d12ffaae54f7317fa8f4f4dfa8ae7b6", + "reference": "f9f63e0e7d12ffaae54f7317fa8f4f4dfa8ae7b6", "shasum": "" }, "require": { "ext-json": "*", "php": "^7.4 || ^8.0", "php-http/discovery": "^1.7", - "psr/http-client": "^1.0" + "psr/http-client": "^1.0", + "symfony/polyfill-php81": "^1.33" }, "require-dev": { "http-interop/http-factory-guzzle": "^1.2.0", @@ -3239,8 +3240,20 @@ ], "authors": [ { - "name": "Clementine", + "name": "Clémentine Urquizar", "email": "clementine@meilisearch.com" + }, + { + "name": "Bruno Casali", + "email": "bruno@meilisearch.com" + }, + { + "name": "Laurent Cazanove", + "email": "lau.cazanove@gmail.com" + }, + { + "name": "Tomas Norkūnas", + "email": "norkunas.tom@gmail.com" } ], "description": "PHP wrapper for the Meilisearch API", @@ -3254,9 +3267,9 @@ ], "support": { "issues": "https://github.com/meilisearch/meilisearch-php/issues", - "source": "https://github.com/meilisearch/meilisearch-php/tree/v1.16.0" + "source": "https://github.com/meilisearch/meilisearch-php/tree/v1.16.1" }, - "time": "2025-09-10T08:50:58+00:00" + "time": "2025-09-18T10:15:45+00:00" }, { "name": "moneyphp/money", @@ -3990,24 +4003,26 @@ }, { "name": "paragonie/constant_time_encoding", - "version": "v3.0.0", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", - "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", "shasum": "" }, "require": { "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^9", - "vimeo/psalm": "^4|^5" + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" }, "type": "library", "autoload": { @@ -4053,7 +4068,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2024-05-08T12:36:18+00:00" + "time": "2025-09-24T15:06:41+00:00" }, { "name": "paragonie/random_compat", @@ -5049,16 +5064,16 @@ }, { "name": "sentry/sentry", - "version": "4.15.2", + "version": "4.16.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "61a2d918e8424b6de4a2e265c15133a00c17db51" + "reference": "c5b086e4235762da175034bc463b0d31cbb38d2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/61a2d918e8424b6de4a2e265c15133a00c17db51", - "reference": "61a2d918e8424b6de4a2e265c15133a00c17db51", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/c5b086e4235762da175034bc463b0d31cbb38d2e", + "reference": "c5b086e4235762da175034bc463b0d31cbb38d2e", "shasum": "" }, "require": { @@ -5122,7 +5137,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.15.2" + "source": "https://github.com/getsentry/sentry-php/tree/4.16.0" }, "funding": [ { @@ -5134,7 +5149,7 @@ "type": "custom" } ], - "time": "2025-09-03T07:23:48+00:00" + "time": "2025-09-22T13:38:03+00:00" }, { "name": "sentry/sentry-laravel", @@ -5813,16 +5828,16 @@ }, { "name": "spatie/robots-txt", - "version": "2.5.1", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/spatie/robots-txt.git", - "reference": "ef85dfaa48372c0a7fdfb144592f95de1a2e9b79" + "reference": "1b59dde3fd4e1b71967b40841369c6e9779282f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/robots-txt/zipball/ef85dfaa48372c0a7fdfb144592f95de1a2e9b79", - "reference": "ef85dfaa48372c0a7fdfb144592f95de1a2e9b79", + "url": "https://api.github.com/repos/spatie/robots-txt/zipball/1b59dde3fd4e1b71967b40841369c6e9779282f3", + "reference": "1b59dde3fd4e1b71967b40841369c6e9779282f3", "shasum": "" }, "require": { @@ -5857,7 +5872,7 @@ ], "support": { "issues": "https://github.com/spatie/robots-txt/issues", - "source": "https://github.com/spatie/robots-txt/tree/2.5.1" + "source": "https://github.com/spatie/robots-txt/tree/2.5.2" }, "funding": [ { @@ -5869,7 +5884,7 @@ "type": "github" } ], - "time": "2025-07-01T07:07:44+00:00" + "time": "2025-09-19T10:37:01+00:00" }, { "name": "spatie/url", @@ -6135,16 +6150,16 @@ }, { "name": "symfony/console", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7" + "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", - "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", + "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", + "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", "shasum": "" }, "require": { @@ -6209,7 +6224,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.3" + "source": "https://github.com/symfony/console/tree/v7.3.4" }, "funding": [ { @@ -6229,7 +6244,7 @@ "type": "tidelift" } ], - "time": "2025-08-25T06:35:40+00:00" + "time": "2025-09-22T15:31:00+00:00" }, { "name": "symfony/css-selector", @@ -6436,16 +6451,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3" + "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/0b31a944fcd8759ae294da4d2808cbc53aebd0c3", - "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/99f81bc944ab8e5dae4f21b4ca9972698bbad0e4", + "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4", "shasum": "" }, "require": { @@ -6493,7 +6508,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.2" + "source": "https://github.com/symfony/error-handler/tree/v7.3.4" }, "funding": [ { @@ -6513,7 +6528,7 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:57+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/event-dispatcher", @@ -6745,16 +6760,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019" + "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019", - "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019", + "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", "shasum": "" }, "require": { @@ -6821,7 +6836,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.3" + "source": "https://github.com/symfony/http-client/tree/v7.3.4" }, "funding": [ { @@ -6841,7 +6856,7 @@ "type": "tidelift" } ], - "time": "2025-08-27T07:45:05+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/http-client-contracts", @@ -6923,16 +6938,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00" + "reference": "c061c7c18918b1b64268771aad04b40be41dd2e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00", - "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c061c7c18918b1b64268771aad04b40be41dd2e6", + "reference": "c061c7c18918b1b64268771aad04b40be41dd2e6", "shasum": "" }, "require": { @@ -6982,7 +6997,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.3" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.4" }, "funding": [ { @@ -7002,20 +7017,20 @@ "type": "tidelift" } ], - "time": "2025-08-20T08:04:18+00:00" + "time": "2025-09-16T08:38:17+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b" + "reference": "b796dffea7821f035047235e076b60ca2446e3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b", - "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b796dffea7821f035047235e076b60ca2446e3cf", + "reference": "b796dffea7821f035047235e076b60ca2446e3cf", "shasum": "" }, "require": { @@ -7100,7 +7115,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.3" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.4" }, "funding": [ { @@ -7120,20 +7135,20 @@ "type": "tidelift" } ], - "time": "2025-08-29T08:23:45+00:00" + "time": "2025-09-27T12:32:17+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575" + "reference": "ab97ef2f7acf0216955f5845484235113047a31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575", - "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575", + "url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d", + "reference": "ab97ef2f7acf0216955f5845484235113047a31d", "shasum": "" }, "require": { @@ -7184,7 +7199,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.3" + "source": "https://github.com/symfony/mailer/tree/v7.3.4" }, "funding": [ { @@ -7204,20 +7219,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-09-17T05:51:54+00:00" }, { "name": "symfony/mime", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" + "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", - "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35", + "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35", "shasum": "" }, "require": { @@ -7272,7 +7287,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.2" + "source": "https://github.com/symfony/mime/tree/v7.3.4" }, "funding": [ { @@ -7292,7 +7307,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2025-09-16T08:38:17+00:00" }, { "name": "symfony/options-resolver", @@ -8108,6 +8123,86 @@ ], "time": "2025-01-02T08:10:11+00:00" }, + { + "name": "symfony/polyfill-php81", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-php83", "version": "v1.33.0", @@ -8433,16 +8528,16 @@ }, { "name": "symfony/process", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "32241012d521e2e8a9d713adb0812bb773b907f1" + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1", - "reference": "32241012d521e2e8a9d713adb0812bb773b907f1", + "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", "shasum": "" }, "require": { @@ -8474,7 +8569,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.3" + "source": "https://github.com/symfony/process/tree/v7.3.4" }, "funding": [ { @@ -8494,7 +8589,7 @@ "type": "tidelift" } ], - "time": "2025-08-18T09:42:54+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -8581,16 +8676,16 @@ }, { "name": "symfony/routing", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4" + "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/7614b8ca5fa89b9cd233e21b627bfc5774f586e4", - "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4", + "url": "https://api.github.com/repos/symfony/routing/zipball/8dc648e159e9bac02b703b9fbd937f19ba13d07c", + "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c", "shasum": "" }, "require": { @@ -8642,7 +8737,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.2" + "source": "https://github.com/symfony/routing/tree/v7.3.4" }, "funding": [ { @@ -8662,7 +8757,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/service-contracts", @@ -8749,16 +8844,16 @@ }, { "name": "symfony/string", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" + "reference": "f96476035142921000338bad71e5247fbc138872" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", - "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", + "reference": "f96476035142921000338bad71e5247fbc138872", "shasum": "" }, "require": { @@ -8773,7 +8868,6 @@ }, "require-dev": { "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", @@ -8816,7 +8910,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.3" + "source": "https://github.com/symfony/string/tree/v7.3.4" }, "funding": [ { @@ -8836,20 +8930,20 @@ "type": "tidelift" } ], - "time": "2025-08-25T06:35:40+00:00" + "time": "2025-09-11T14:36:48+00:00" }, { "name": "symfony/translation", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e0837b4cbcef63c754d89a4806575cada743a38d" + "reference": "ec25870502d0c7072d086e8ffba1420c85965174" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d", - "reference": "e0837b4cbcef63c754d89a4806575cada743a38d", + "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174", + "reference": "ec25870502d0c7072d086e8ffba1420c85965174", "shasum": "" }, "require": { @@ -8916,7 +9010,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.3" + "source": "https://github.com/symfony/translation/tree/v7.3.4" }, "funding": [ { @@ -8936,7 +9030,7 @@ "type": "tidelift" } ], - "time": "2025-08-01T21:02:37+00:00" + "time": "2025-09-07T11:39:36+00:00" }, { "name": "symfony/translation-contracts", @@ -9092,16 +9186,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.3", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f" + "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", - "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", + "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", "shasum": "" }, "require": { @@ -9155,7 +9249,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.4" }, "funding": [ { @@ -9175,7 +9269,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/yaml", @@ -9678,16 +9772,16 @@ }, { "name": "zircote/swagger-php", - "version": "5.3.2", + "version": "5.4.0", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "d8fa9dc4c3b2fc8651ae780021bb9719b1e63d40" + "reference": "e25c377ec04db4d2b91186e2debaa1fb135f5cc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/d8fa9dc4c3b2fc8651ae780021bb9719b1e63d40", - "reference": "d8fa9dc4c3b2fc8651ae780021bb9719b1e63d40", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/e25c377ec04db4d2b91186e2debaa1fb135f5cc5", + "reference": "e25c377ec04db4d2b91186e2debaa1fb135f5cc5", "shasum": "" }, "require": { @@ -9758,9 +9852,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/5.3.2" + "source": "https://github.com/zircote/swagger-php/tree/5.4.0" }, - "time": "2025-08-25T21:57:16+00:00" + "time": "2025-09-12T03:49:27+00:00" } ], "packages-dev": [ @@ -10077,16 +10171,16 @@ }, { "name": "larastan/larastan", - "version": "v3.7.1", + "version": "v3.7.2", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "2e653fd19585a825e283b42f38378b21ae481cc7" + "reference": "a761859a7487bd7d0cb8b662a7538a234d5bb5ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/2e653fd19585a825e283b42f38378b21ae481cc7", - "reference": "2e653fd19585a825e283b42f38378b21ae481cc7", + "url": "https://api.github.com/repos/larastan/larastan/zipball/a761859a7487bd7d0cb8b662a7538a234d5bb5ae", + "reference": "a761859a7487bd7d0cb8b662a7538a234d5bb5ae", "shasum": "" }, "require": { @@ -10100,7 +10194,7 @@ "illuminate/pipeline": "^11.44.2 || ^12.4.1", "illuminate/support": "^11.44.2 || ^12.4.1", "php": "^8.2", - "phpstan/phpstan": "^2.1.23" + "phpstan/phpstan": "^2.1.28" }, "require-dev": { "doctrine/coding-standard": "^13", @@ -10154,7 +10248,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v3.7.1" + "source": "https://github.com/larastan/larastan/tree/v3.7.2" }, "funding": [ { @@ -10162,20 +10256,20 @@ "type": "github" } ], - "time": "2025-09-10T19:42:11+00:00" + "time": "2025-09-19T09:03:05+00:00" }, { "name": "laravel/pint", - "version": "v1.24.0", + "version": "v1.25.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a" + "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/0345f3b05f136801af8c339f9d16ef29e6b4df8a", - "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a", + "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9", + "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9", "shasum": "" }, "require": { @@ -10186,9 +10280,9 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.82.2", - "illuminate/view": "^11.45.1", - "larastan/larastan": "^3.5.0", + "friendsofphp/php-cs-fixer": "^3.87.2", + "illuminate/view": "^11.46.0", + "larastan/larastan": "^3.7.1", "laravel-zero/framework": "^11.45.0", "mockery/mockery": "^1.6.12", "nunomaduro/termwind": "^2.3.1", @@ -10199,9 +10293,6 @@ ], "type": "project", "autoload": { - "files": [ - "overrides/Runner/Parallel/ProcessFactory.php" - ], "psr-4": { "App\\": "app/", "Database\\Seeders\\": "database/seeders/", @@ -10231,7 +10322,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2025-07-10T18:09:32+00:00" + "time": "2025-09-19T02:57:12+00:00" }, { "name": "mockery/mockery", @@ -10668,16 +10759,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.25", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "4087d28bd252895874e174d65e26b2c202ed893a" - }, + "version": "2.1.30", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4087d28bd252895874e174d65e26b2c202ed893a", - "reference": "4087d28bd252895874e174d65e26b2c202ed893a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a4a7f159927983dd4f7c8020ed227d80b7f39d7d", + "reference": "a4a7f159927983dd4f7c8020ed227d80b7f39d7d", "shasum": "" }, "require": { @@ -10722,7 +10808,7 @@ "type": "github" } ], - "time": "2025-09-12T14:26:42+00:00" + "time": "2025-10-02T16:07:52+00:00" }, { "name": "phpunit/php-code-coverage", @@ -11061,16 +11147,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.38", + "version": "11.5.42", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "5bd0e4f64a2261b7ade7054c51547beaf2d99e43" + "reference": "1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5bd0e4f64a2261b7ade7054c51547beaf2d99e43", - "reference": "5bd0e4f64a2261b7ade7054c51547beaf2d99e43", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c", + "reference": "1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c", "shasum": "" }, "require": { @@ -11094,7 +11180,7 @@ "sebastian/comparator": "^6.3.2", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.1", - "sebastian/exporter": "^6.3.0", + "sebastian/exporter": "^6.3.2", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", "sebastian/type": "^5.1.3", @@ -11142,7 +11228,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.38" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.42" }, "funding": [ { @@ -11166,7 +11252,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:34:07+00:00" + "time": "2025-09-28T12:09:13+00:00" }, { "name": "sebastian/cli-parser", @@ -11633,16 +11719,16 @@ }, { "name": "sebastian/exporter", - "version": "6.3.0", + "version": "6.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", "shasum": "" }, "require": { @@ -11656,7 +11742,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -11699,15 +11785,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2024-12-05T09:17:50+00:00" + "time": "2025-09-24T06:12:51+00:00" }, { "name": "sebastian/global-state", diff --git a/config/auth.php b/config/auth.php index 2462b3ed..aeffd47d 100644 --- a/config/auth.php +++ b/config/auth.php @@ -39,9 +39,6 @@ 'web' => [ 'driver' => 'session', 'provider' => 'users', - ], - 'force-login' => [ - 'driver' => 'no-auth' ] ], diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index bfa91552..965fa9b1 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -5829,7 +5829,7 @@ paths: properties: data: { $ref: '#/components/schemas/APIError' } type: object - '/public/{barId}': + '/public/{slugOrId}': get: tags: - Public @@ -5838,12 +5838,12 @@ paths: operationId: showPublicBar parameters: - - name: barId + name: slugOrId in: path description: 'Database id of bar' required: true schema: - type: number + type: string - name: page in: query @@ -5888,7 +5888,7 @@ paths: data: { $ref: '#/components/schemas/APIError' } type: object security: [] - '/public/{barId}/cocktails': + '/public/{slugOrId}/cocktails': get: tags: - Public @@ -5897,12 +5897,12 @@ paths: operationId: listPublicBarCocktails parameters: - - name: barId + name: slugOrId in: path - description: 'Database id of bar' + description: 'Database id or slug of bar' required: true schema: - type: number + type: string - name: page in: query @@ -5983,7 +5983,7 @@ paths: data: { $ref: '#/components/schemas/APIError' } type: object security: [] - '/public/{barId}/cocktails/{slugOrPublicId}': + '/public/{slugOrId}/cocktails/{slugOrPublicId}': get: tags: - Public @@ -5992,12 +5992,12 @@ paths: operationId: showPublicBarCocktail parameters: - - name: barId + name: slugOrId in: path description: 'Database id of bar' required: true schema: - type: number + type: string - name: slugOrPublicId in: path @@ -9986,6 +9986,7 @@ components: - subtitle - description - images + - is_menu_enabled properties: id: description: 'Unique number that can be used to reference a specific bar.' @@ -10016,6 +10017,10 @@ components: type: array items: $ref: '#/components/schemas/PublicImageResource' + is_menu_enabled: + description: 'Whether the bar has enabled its menu for public viewing' + type: boolean + example: true type: object PublicCocktailResource: description: 'Public details about a cocktail' From 00b15bdd843bd1ed82b75a04d83e3d7476b0cbc5 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sat, 11 Oct 2025 11:00:43 +0200 Subject: [PATCH 19/25] csfix --- app/Http/Controllers/BarController.php | 2 +- app/Http/Controllers/SubscriptionController.php | 2 +- app/Models/Bar.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/BarController.php b/app/Http/Controllers/BarController.php index b1a553cb..bea54637 100644 --- a/app/Http/Controllers/BarController.php +++ b/app/Http/Controllers/BarController.php @@ -4,6 +4,7 @@ namespace Kami\Cocktail\Http\Controllers; +use Throwable; use Illuminate\Http\Request; use Illuminate\Http\Response; use Kami\Cocktail\Models\Bar; @@ -23,7 +24,6 @@ use Illuminate\Http\Resources\Json\JsonResource; use Kami\Cocktail\Http\Resources\BarMembershipResource; use Kami\Cocktail\OpenAPI\Schemas\BarRequest as SchemasBarRequest; -use Throwable; class BarController extends Controller { diff --git a/app/Http/Controllers/SubscriptionController.php b/app/Http/Controllers/SubscriptionController.php index 3a6f0b70..864b447d 100644 --- a/app/Http/Controllers/SubscriptionController.php +++ b/app/Http/Controllers/SubscriptionController.php @@ -8,8 +8,8 @@ use Illuminate\Http\Request; use OpenApi\Attributes as OAT; use Illuminate\Http\JsonResponse; -use Illuminate\Support\Facades\Log; use Kami\Cocktail\OpenAPI as BAO; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; use Kami\Cocktail\Mail\SubscriptionChanged; use Kami\Cocktail\Http\Resources\UserSubscriptionResource; diff --git a/app/Models/Bar.php b/app/Models/Bar.php index d90839b0..6d44a6f8 100644 --- a/app/Models/Bar.php +++ b/app/Models/Bar.php @@ -15,10 +15,10 @@ use Kami\Cocktail\Models\Enums\BarStatusEnum; use Kami\Cocktail\Services\Image\ImageService; use Kami\Cocktail\Services\MeilisearchService; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Database\Eloquent\Relations\HasOne; class Bar extends Model implements UploadableInterface { From e749b0480e97cbfdbd2f2cd98b55df5dd1269001 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 12 Oct 2025 17:59:28 +0200 Subject: [PATCH 20/25] Update CHANGELOG.md --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e0ee28e..76ecb5a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# v5.9.0 +# New +- Added `public/{slugOrId}` endpoints + - You can now access public bar data via `public/{slugOrId}` endpoints + - Added GET `public/{slugOrId}/menu` endpoint + - Added GET `public/{slugOrId}/cocktails` endpoint + - Added GET `public/{slugOrId}/cocktails/{cocktailId}` endpoint + - Added `is_public` property to `Bar` schema + - If set to `true`, bar will expose public endpoints `/public/{barId}/*` +- Added `is_menu_enabled` to public `Bar` schema + +## Fixes +- Fixed search driver indexing calls when not using search driver +- Default ingredient unit bar setting is not correctly applied when importing data via datapack +- Fixed unique constraint violation when adding ingredients into bar shelf + # v5.8.1 ## Fixes - Fixed missing API ability on `import/cocktail` endpoint From 02648050f7b6682e5d4b481252c4ec860864cc99 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 12 Oct 2025 17:59:32 +0200 Subject: [PATCH 21/25] Update composer.lock --- composer.lock | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/composer.lock b/composer.lock index ccd670b9..2a30b87a 100644 --- a/composer.lock +++ b/composer.lock @@ -1631,30 +1631,30 @@ }, { "name": "laminas/laminas-stdlib", - "version": "3.20.0", + "version": "3.21.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" + "reference": "b1c81514cfe158aadf724c42b34d3d0a8164c096" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", - "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/b1c81514cfe158aadf724c42b34d3d0a8164c096", + "reference": "b1c81514cfe158aadf724c42b34d3d0a8164c096", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^3.0", - "phpbench/phpbench": "^1.3.1", - "phpunit/phpunit": "^10.5.38", - "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.26.1" + "laminas/laminas-coding-standard": "^3.1.0", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^11.5.42", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.13.1" }, "type": "library", "autoload": { @@ -1686,7 +1686,7 @@ "type": "community_bridge" } ], - "time": "2024-10-29T13:46:07+00:00" + "time": "2025-10-11T18:13:12+00:00" }, { "name": "laravel/cashier-paddle", @@ -1772,16 +1772,16 @@ }, { "name": "laravel/framework", - "version": "v12.32.5", + "version": "v12.33.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a" + "reference": "124efc5f09d4668a4dc13f94a1018c524a58bcb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/77b2740391cd2a825ba59d6fada45e9b8b9bcc5a", - "reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a", + "url": "https://api.github.com/repos/laravel/framework/zipball/124efc5f09d4668a4dc13f94a1018c524a58bcb1", + "reference": "124efc5f09d4668a4dc13f94a1018c524a58bcb1", "shasum": "" }, "require": { @@ -1987,20 +1987,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-09-30T17:39:22+00:00" + "time": "2025-10-07T14:30:39+00:00" }, { "name": "laravel/horizon", - "version": "v5.34.0", + "version": "v5.35.2", "source": { "type": "git", "url": "https://github.com/laravel/horizon.git", - "reference": "c110ff6ed494b57beb6b4102a92bb4bf896bb774" + "reference": "11f9a980d84de56402dec19cf1e78050b211fcef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/horizon/zipball/c110ff6ed494b57beb6b4102a92bb4bf896bb774", - "reference": "c110ff6ed494b57beb6b4102a92bb4bf896bb774", + "url": "https://api.github.com/repos/laravel/horizon/zipball/11f9a980d84de56402dec19cf1e78050b211fcef", + "reference": "11f9a980d84de56402dec19cf1e78050b211fcef", "shasum": "" }, "require": { @@ -2065,9 +2065,9 @@ ], "support": { "issues": "https://github.com/laravel/horizon/issues", - "source": "https://github.com/laravel/horizon/tree/v5.34.0" + "source": "https://github.com/laravel/horizon/tree/v5.35.2" }, - "time": "2025-09-12T15:15:45+00:00" + "time": "2025-10-08T12:50:15+00:00" }, { "name": "laravel/prompts", @@ -2194,16 +2194,16 @@ }, { "name": "laravel/scout", - "version": "v10.19.0", + "version": "v10.19.1", "source": { "type": "git", "url": "https://github.com/laravel/scout.git", - "reference": "996b2a8b5ccc583e7df667c8aac924a46bc8bdd3" + "reference": "bc8dbffc06472e28147ee739aec95fdf653f9d91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/scout/zipball/996b2a8b5ccc583e7df667c8aac924a46bc8bdd3", - "reference": "996b2a8b5ccc583e7df667c8aac924a46bc8bdd3", + "url": "https://api.github.com/repos/laravel/scout/zipball/bc8dbffc06472e28147ee739aec95fdf653f9d91", + "reference": "bc8dbffc06472e28147ee739aec95fdf653f9d91", "shasum": "" }, "require": { @@ -2271,7 +2271,7 @@ "issues": "https://github.com/laravel/scout/issues", "source": "https://github.com/laravel/scout" }, - "time": "2025-08-26T14:24:24+00:00" + "time": "2025-10-07T14:48:20+00:00" }, { "name": "laravel/serializable-closure", @@ -4276,16 +4276,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.46", + "version": "3.0.47", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" + "reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", - "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/9d6ca36a6c2dd434765b1071b2644a1c683b385d", + "reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d", "shasum": "" }, "require": { @@ -4366,7 +4366,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.47" }, "funding": [ { @@ -4382,7 +4382,7 @@ "type": "tidelift" } ], - "time": "2025-06-26T16:29:55+00:00" + "time": "2025-10-06T01:07:24+00:00" }, { "name": "promphp/prometheus_client_php", @@ -9772,16 +9772,16 @@ }, { "name": "zircote/swagger-php", - "version": "5.4.0", + "version": "5.4.2", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "e25c377ec04db4d2b91186e2debaa1fb135f5cc5" + "reference": "4f6bac8bdb9e762c6a4de12ef62160d4e5a17caa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/e25c377ec04db4d2b91186e2debaa1fb135f5cc5", - "reference": "e25c377ec04db4d2b91186e2debaa1fb135f5cc5", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/4f6bac8bdb9e762c6a4de12ef62160d4e5a17caa", + "reference": "4f6bac8bdb9e762c6a4de12ef62160d4e5a17caa", "shasum": "" }, "require": { @@ -9852,9 +9852,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/5.4.0" + "source": "https://github.com/zircote/swagger-php/tree/5.4.2" }, - "time": "2025-09-12T03:49:27+00:00" + "time": "2025-10-09T01:32:43+00:00" } ], "packages-dev": [ @@ -10759,11 +10759,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.30", + "version": "2.1.31", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a4a7f159927983dd4f7c8020ed227d80b7f39d7d", - "reference": "a4a7f159927983dd4f7c8020ed227d80b7f39d7d", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96", + "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96", "shasum": "" }, "require": { @@ -10808,7 +10808,7 @@ "type": "github" } ], - "time": "2025-10-02T16:07:52+00:00" + "time": "2025-10-10T14:14:11+00:00" }, { "name": "phpunit/php-code-coverage", From 5ebc4cf917ccdb869dccd33dae783871ef462002 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 12 Oct 2025 17:59:47 +0200 Subject: [PATCH 22/25] csfix --- .../Controllers/Public/MenuController.php | 14 ++++- app/Http/Resources/Public/BarResource.php | 2 +- app/Models/Ingredient.php | 2 +- docs/openapi-generated.yaml | 53 +++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Public/MenuController.php b/app/Http/Controllers/Public/MenuController.php index b25e8cc9..b214da56 100644 --- a/app/Http/Controllers/Public/MenuController.php +++ b/app/Http/Controllers/Public/MenuController.php @@ -5,16 +5,26 @@ namespace Kami\Cocktail\Http\Controllers\Public; use Kami\Cocktail\Models\Menu; +use OpenApi\Attributes as OAT; +use Kami\Cocktail\OpenAPI as BAO; use Kami\Cocktail\Http\Controllers\Controller; use Kami\Cocktail\Http\Resources\MenuPublicResource; class MenuController extends Controller { - public function show(string $barId): MenuPublicResource + #[OAT\Get(path: '/public/{slugOrId}/menu', tags: ['Public'], operationId: 'showPublicBarMenu', description: 'Show a public bar menu details', summary: 'Show public menu', parameters: [ + new OAT\Parameter(name: 'slugOrId', in: 'path', required: true, description: 'Database id or slug of bar', schema: new OAT\Schema(type: 'string')), + ], security: [])] + #[BAO\SuccessfulResponse(content: [ + new BAO\WrapObjectWithData(MenuPublicResource::class), + ])] + #[BAO\NotFoundResponse] + public function show(string $barSlugOrId): MenuPublicResource { $menu = Menu::select('menus.*') - ->where('bars.id', $barId) ->where('menus.is_enabled', true) + ->where('bars.id', $barSlugOrId) + ->orWhere('bars.slug', $barSlugOrId) ->join('bars', 'bars.id', '=', 'menus.bar_id') ->join('menu_cocktails', 'menu_cocktails.menu_id', '=', 'menus.id') ->orderBy('menu_cocktails.sort', 'asc') diff --git a/app/Http/Resources/Public/BarResource.php b/app/Http/Resources/Public/BarResource.php index c8b38ce6..e245cdb6 100644 --- a/app/Http/Resources/Public/BarResource.php +++ b/app/Http/Resources/Public/BarResource.php @@ -41,7 +41,7 @@ public function toArray($request) 'subtitle' => $this->subtitle, 'description' => $this->description, 'images' => ImageResource::collection($this->images), - 'is_menu_enabled' => $this->menu?->is_enabled ?? false, + 'is_menu_enabled' => $this->menu->is_enabled ?? false, ]; } } diff --git a/app/Models/Ingredient.php b/app/Models/Ingredient.php index e273f7ef..a937c7ef 100644 --- a/app/Models/Ingredient.php +++ b/app/Models/Ingredient.php @@ -252,7 +252,7 @@ public function getIngredientsUsedAsSubstituteFor(): Collection /** * Return all ingredients that can be substituted with this ingredient * - * @return Collection + * @return Collection */ public function getCanBeSubstitutedWithIngredients(): Collection { diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index 965fa9b1..879c28af 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -6043,6 +6043,59 @@ paths: data: { $ref: '#/components/schemas/APIError' } type: object security: [] + '/public/{slugOrId}/menu': + get: + tags: + - Public + summary: 'Show public menu' + description: 'Show a public bar menu details' + operationId: showPublicBarMenu + parameters: + - + name: slugOrId + in: path + description: 'Database id or slug of bar' + required: true + schema: + type: string + responses: + '200': + description: 'Successful response' + headers: + x-ratelimit-limit: + description: 'Max number of attempts.' + schema: + type: integer + x-ratelimit-remaining: + description: 'Remaining number of attempts.' + schema: + type: integer + content: + application/json: + schema: + required: + - data + properties: + data: { $ref: '#/components/schemas/MenuPublic' } + type: object + '404': + description: 'Resource record not found.' + headers: + x-ratelimit-limit: + description: 'Max number of attempts.' + schema: + type: integer + x-ratelimit-remaining: + description: 'Remaining number of attempts.' + schema: + type: integer + content: + application/json: + schema: + properties: + data: { $ref: '#/components/schemas/APIError' } + type: object + security: [] '/cocktails/{id}/ratings': post: tags: From b08bc401d1b9bf80f1a57cd8b22ffefe26976adc Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 12 Oct 2025 20:56:48 +0200 Subject: [PATCH 23/25] Fix spec --- app/Http/Resources/Public/CocktailResource.php | 4 ++-- docs/openapi-generated.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Http/Resources/Public/CocktailResource.php b/app/Http/Resources/Public/CocktailResource.php index fdb16e84..2632ebbb 100644 --- a/app/Http/Resources/Public/CocktailResource.php +++ b/app/Http/Resources/Public/CocktailResource.php @@ -31,8 +31,8 @@ new OAT\Property(property: 'glass', type: 'string', nullable: true, example: 'Highball glass', description: 'Type of glass used for the cocktail'), new OAT\Property(property: 'utensils', type: 'array', items: new OAT\Items(type: 'string'), description: 'Utensils used for preparing the cocktail'), new OAT\Property(property: 'method', type: 'string', nullable: true, example: 'Shaken', description: 'Method of preparation for the cocktail'), - new OAT\Property(property: 'method_dilution_percentage', type: 'number', nullable: true, example: '12', description: 'Dilution percentage associated with the preparation method'), - new OAT\Property(property: 'volume_ml', type: 'number', nullable: true, example: '120', description: 'Total volume of the cocktail in milliliters'), + new OAT\Property(property: 'method_dilution_percentage', type: 'number', nullable: true, example: 12, description: 'Dilution percentage associated with the preparation method'), + new OAT\Property(property: 'volume_ml', type: 'number', nullable: true, example: 120d, description: 'Total volume of the cocktail in milliliters'), new OAT\Property(property: 'created_at', type: 'string', format: 'date-time', example: '2023-10-01T12:00:00Z', description: 'Date and time when the cocktail was created'), new OAT\Property(property: 'in_bar_shelf', type: 'boolean', example: true, description: 'Indicates if the cocktail can be made in the current bar'), new OAT\Property(property: 'abv', type: 'number', format: 'float', nullable: true, example: 0.15, description: 'Alcohol by volume percentage of the cocktail'), diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index 879c28af..684f488f 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -10169,13 +10169,13 @@ components: type: - number - 'null' - example: '12' + example: 12 volume_ml: description: 'Total volume of the cocktail in milliliters' type: - number - 'null' - example: '120' + example: 120 created_at: description: 'Date and time when the cocktail was created' type: string From 3cb21c9d859d525dbfe5760209ff572d1eaca05b Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Sun, 12 Oct 2025 21:00:55 +0200 Subject: [PATCH 24/25] fix typo --- app/Http/Resources/Public/CocktailResource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Resources/Public/CocktailResource.php b/app/Http/Resources/Public/CocktailResource.php index 2632ebbb..10225ca1 100644 --- a/app/Http/Resources/Public/CocktailResource.php +++ b/app/Http/Resources/Public/CocktailResource.php @@ -32,7 +32,7 @@ new OAT\Property(property: 'utensils', type: 'array', items: new OAT\Items(type: 'string'), description: 'Utensils used for preparing the cocktail'), new OAT\Property(property: 'method', type: 'string', nullable: true, example: 'Shaken', description: 'Method of preparation for the cocktail'), new OAT\Property(property: 'method_dilution_percentage', type: 'number', nullable: true, example: 12, description: 'Dilution percentage associated with the preparation method'), - new OAT\Property(property: 'volume_ml', type: 'number', nullable: true, example: 120d, description: 'Total volume of the cocktail in milliliters'), + new OAT\Property(property: 'volume_ml', type: 'number', nullable: true, example: 120, description: 'Total volume of the cocktail in milliliters'), new OAT\Property(property: 'created_at', type: 'string', format: 'date-time', example: '2023-10-01T12:00:00Z', description: 'Date and time when the cocktail was created'), new OAT\Property(property: 'in_bar_shelf', type: 'boolean', example: true, description: 'Indicates if the cocktail can be made in the current bar'), new OAT\Property(property: 'abv', type: 'number', format: 'float', nullable: true, example: 0.15, description: 'Alcohol by volume percentage of the cocktail'), From 00b4d73e19048e5594b912e64d879f73e12804d3 Mon Sep 17 00:00:00 2001 From: Karlo Mikus Date: Wed, 15 Oct 2025 14:59:59 +0200 Subject: [PATCH 25/25] Update schema --- CHANGELOG.md | 2 +- app/Http/Controllers/Public/BarController.php | 2 +- app/Http/Controllers/Public/CocktailController.php | 13 ++++++------- app/Http/Controllers/Public/MenuController.php | 2 +- app/Http/Resources/BarResource.php | 2 +- app/Models/Bar.php | 10 ++++++++++ docs/openapi-generated.yaml | 10 +++++----- 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76ecb5a3..26ebb222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # v5.9.0 # New -- Added `public/{slugOrId}` endpoints +- Documented `public/{slugOrId}` endpoints - You can now access public bar data via `public/{slugOrId}` endpoints - Added GET `public/{slugOrId}/menu` endpoint - Added GET `public/{slugOrId}/cocktails` endpoint diff --git a/app/Http/Controllers/Public/BarController.php b/app/Http/Controllers/Public/BarController.php index b70bcc12..8cab6f09 100644 --- a/app/Http/Controllers/Public/BarController.php +++ b/app/Http/Controllers/Public/BarController.php @@ -23,7 +23,7 @@ class BarController extends Controller public function show(string $slugOrId): BarResource { $bar = Bar::where('slug', $slugOrId)->orWhere('id', $slugOrId)->firstOrFail(); - if (!$bar->is_public) { + if (!$bar->isPublic()) { abort(404); } diff --git a/app/Http/Controllers/Public/CocktailController.php b/app/Http/Controllers/Public/CocktailController.php index 4b929c88..903a05f7 100644 --- a/app/Http/Controllers/Public/CocktailController.php +++ b/app/Http/Controllers/Public/CocktailController.php @@ -39,7 +39,7 @@ class CocktailController extends Controller public function index(Request $request, string $slugOrId): JsonResource { $bar = Bar::where('slug', $slugOrId)->orWhere('id', $slugOrId)->firstOrFail(); - if (!$bar->is_public) { + if (!$bar->isPublic()) { abort(404); } @@ -66,23 +66,22 @@ public function index(Request $request, string $slugOrId): JsonResource return CocktailResource::collection($cocktails->withQueryString()); } - #[OAT\Get(path: '/public/{slugOrId}/cocktails/{slugOrPublicId}', tags: ['Public'], operationId: 'showPublicBarCocktail', description: 'Show public information about cocktail. If valid public ID is provided it will used, if not it will use cocktail slug.', summary: 'Show cocktail', parameters: [ + #[OAT\Get(path: '/public/{slugOrId}/cocktails/{cocktailSlug}', tags: ['Public'], operationId: 'showPublicBarCocktail', description: 'Show public information about cocktail.', summary: 'Show cocktail', parameters: [ new OAT\Parameter(name: 'slugOrId', in: 'path', required: true, description: 'Database id of bar', schema: new OAT\Schema(type: 'string')), - new OAT\Parameter(name: 'slugOrPublicId', in: 'path', required: true, description: 'Cocktail slug or public id (ULID)', schema: new OAT\Schema(type: 'string')), + new OAT\Parameter(name: 'cocktailSlug', in: 'path', required: true, description: 'Cocktail slug', schema: new OAT\Schema(type: 'string')), ], security: [])] #[BAO\SuccessfulResponse(content: [ new BAO\WrapObjectWithData(CocktailResource::class), ])] #[BAO\NotFoundResponse] - public function show(string $barId, string $slugOrPublicId): CocktailResource + public function show(string $barId, string $cocktailSlug): CocktailResource { $bar = Bar::where('slug', $barId)->orWhere('id', $barId)->firstOrFail(); - if (!$bar->is_public) { + if (!$bar->isPublic()) { abort(404); } - $cocktail = Cocktail::where('public_id', $slugOrPublicId) - ->orWhere('slug', $slugOrPublicId) + $cocktail = Cocktail::where('slug', $cocktailSlug) ->with('ingredients.ingredient', 'ingredients.substitutes.ingredient', 'images', 'tags', 'utensils') ->firstOrFail(); diff --git a/app/Http/Controllers/Public/MenuController.php b/app/Http/Controllers/Public/MenuController.php index b214da56..bfb4a9be 100644 --- a/app/Http/Controllers/Public/MenuController.php +++ b/app/Http/Controllers/Public/MenuController.php @@ -12,7 +12,7 @@ class MenuController extends Controller { - #[OAT\Get(path: '/public/{slugOrId}/menu', tags: ['Public'], operationId: 'showPublicBarMenu', description: 'Show a public bar menu details', summary: 'Show public menu', parameters: [ + #[OAT\Get(path: '/public/{slugOrId}/menu', tags: ['Public'], operationId: 'showPublicBarMenu', description: 'Show a public bar menu details. The bar must have menu enabled.', summary: 'Show public menu', parameters: [ new OAT\Parameter(name: 'slugOrId', in: 'path', required: true, description: 'Database id or slug of bar', schema: new OAT\Schema(type: 'string')), ], security: [])] #[BAO\SuccessfulResponse(content: [ diff --git a/app/Http/Resources/BarResource.php b/app/Http/Resources/BarResource.php index 97038ccc..c37b9246 100644 --- a/app/Http/Resources/BarResource.php +++ b/app/Http/Resources/BarResource.php @@ -99,7 +99,7 @@ public function toArray($request) $this->relationLoaded('images'), fn () => ImageResource::collection($this->images) ), - 'is_public' => (bool) $this->is_public, + 'is_public' => $this->is_public, ]; } } diff --git a/app/Models/Bar.php b/app/Models/Bar.php index 6d44a6f8..b2b0ec35 100644 --- a/app/Models/Bar.php +++ b/app/Models/Bar.php @@ -186,6 +186,16 @@ public function isAccessible(): bool return $this->status !== BarStatusEnum::Deactivated->value; } + public function isProvisioning(): bool + { + return $this->status === BarStatusEnum::Provisioning->value; + } + + public function isPublic(): bool + { + return $this->is_public && $this->isAccessible() && !$this->isProvisioning(); + } + public function getIngredientsDirectory(): string { return 'ingredients/' . $this->id . '/'; diff --git a/docs/openapi-generated.yaml b/docs/openapi-generated.yaml index 684f488f..407d1900 100644 --- a/docs/openapi-generated.yaml +++ b/docs/openapi-generated.yaml @@ -5983,12 +5983,12 @@ paths: data: { $ref: '#/components/schemas/APIError' } type: object security: [] - '/public/{slugOrId}/cocktails/{slugOrPublicId}': + '/public/{slugOrId}/cocktails/{cocktailSlug}': get: tags: - Public summary: 'Show cocktail' - description: 'Show public information about cocktail. If valid public ID is provided it will used, if not it will use cocktail slug.' + description: 'Show public information about cocktail.' operationId: showPublicBarCocktail parameters: - @@ -5999,9 +5999,9 @@ paths: schema: type: string - - name: slugOrPublicId + name: cocktailSlug in: path - description: 'Cocktail slug or public id (ULID)' + description: 'Cocktail slug' required: true schema: type: string @@ -6048,7 +6048,7 @@ paths: tags: - Public summary: 'Show public menu' - description: 'Show a public bar menu details' + description: 'Show a public bar menu details. The bar must have menu enabled.' operationId: showPublicBarMenu parameters: -