Skip to content

Commit

Permalink
Merge pull request #377 from karlomikus/develop
Browse files Browse the repository at this point in the history
Bugfix/optimization release
  • Loading branch information
karlomikus authored Dec 15, 2024
2 parents 715a2ad + 2beb876 commit 7f5f5ec
Show file tree
Hide file tree
Showing 25 changed files with 810 additions and 507 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# v4.2.4
## Changes
- Optimized ingredients list query
- Moved SQLite optimizations from bash to backend

## Fixed
- Fixed missing rate limit for imports
- Fixed missing max images validation fro cloud instance
- Fixed markdown export encoding special characters
- Fixed missing complex ingredients on import

# v4.2.3
## Fixed
- Fix unhandled exception when menu cocktail has `null` as currency

# v4.2.2
## Fixed
- Login endpoint now requires confirmation if `mail_require_confirmation` is enabled
Expand Down
47 changes: 47 additions & 0 deletions app/Console/Commands/BarAnon.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Kami\Cocktail\Console\Commands;

use Kami\Cocktail\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;

class BarAnon extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'bar:anon';

/**
* The console command description.
*
* @var string
*/
protected $description = '[DEV] Anonymize data';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$users = User::all();

foreach ($users as $user) {
$user->email = 'email' . $user->id . '@example.com';
$user->name = 'User ' . $user->id;
$user->password = Hash::make('Test12345');
$user->save();
}

$this->output->success('Done!');

return Command::SUCCESS;
}
}
14 changes: 14 additions & 0 deletions app/External/Import/FromDataPack.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ private function importIngredients(Filesystem $dataDisk, Bar $bar, User $user):

$ingredientsToInsert = [];
$parentIngredientsToInsert = [];
$ingredientPartsToInsert = [];
$imagesToInsert = [];
$barImagesDir = $bar->getIngredientsDirectory();
$this->uploadsDisk->makeDirectory($barImagesDir);
Expand Down Expand Up @@ -154,6 +155,10 @@ private function importIngredients(Filesystem $dataDisk, Bar $bar, User $user):
$parentIngredientsToInsert[$slug] = $externalIngredient->parentId . '-' . $bar->id;
}

foreach ($externalIngredient->ingredientParts as $ingredientPart) {
$ingredientPartsToInsert[$slug][] = $ingredientPart->id . '-' . $bar->id;
}

// For performance, manually copy the files and create image references
foreach ($externalIngredient->images as $image) {
$baseSrcImagePath = $filePath . $image->getLocalFilePath();
Expand Down Expand Up @@ -193,6 +198,15 @@ private function importIngredients(Filesystem $dataDisk, Bar $bar, User $user):
}
}

if (array_key_exists($ingredient->slug, $ingredientPartsToInsert)) {
foreach ($ingredientPartsToInsert[$ingredient->slug] as $partSlug) {
$ingredientPartId = DB::table('ingredients')->where('slug', $partSlug)->where('bar_id', $bar->id)->first('id');
if (isset($ingredientPartId->id)) {
DB::table('complex_ingredients')->insert(['main_ingredient_id' => $ingredient->id, 'ingredient_id' => $ingredientPartId->id]);
}
}
}

if (in_array($ingredient->slug, $this->barShelf)) {
DB::table('bar_ingredients')->insert(['ingredient_id' => $ingredient->id, 'bar_id' => $bar->id]);
}
Expand Down
16 changes: 10 additions & 6 deletions app/Http/Controllers/BarController.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,21 @@ public function index(Request $request): JsonResource
#[BAO\NotFoundResponse]
public function show(Request $request, int $id): JsonResource
{
$bar = Bar::findOrFail($id);
$bar = Cache::remember('ba:bar:' . $id, 60 * 60 * 24, function () use ($id) {
$bar = Bar::findOrFail($id);

if (!$bar->slug) {
$bar->generateSlug();
$bar->save();
}

return $bar;
});

if ($request->user()->cannot('show', $bar)) {
abort(403);
}

if (!$bar->slug) {
$bar->generateSlug();
$bar->save();
}

$bar->load('createdUser', 'updatedUser', 'images');

return new BarResource($bar);
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Filters/IngredientQueryFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public function __construct(IngredientRepository $ingredientQuery)
])
->allowedIncludes(['parentIngredient', 'varieties', 'prices', 'category', 'ingredientParts', 'images'])
->withCount('cocktails')
->filterByBar('ingredients');
->filterByBar('ingredients')
->with('bar.shelfIngredients');
}
}
21 changes: 10 additions & 11 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,18 @@ class Kernel extends HttpKernel
*/
protected $middlewareGroups = [
'web' => [
\Kami\Cocktail\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Kami\Cocktail\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// \Kami\Cocktail\Http\Middleware\EncryptCookies::class,
// \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// \Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\View\Middleware\ShareErrorsFromSession::class,
// \Kami\Cocktail\Http\Middleware\VerifyCsrfToken::class,
// \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

'api' => [
\Kami\Cocktail\Http\Middleware\DisablePostOnDemoEnv::class,
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// \Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];

Expand All @@ -55,12 +54,12 @@ class Kernel extends HttpKernel
*/
protected $routeMiddleware = [
'auth' => \Kami\Cocktail\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
// 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
// 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \Kami\Cocktail\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
// 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Kami\Cocktail\Http\Middleware\ValidateSignature::class,
// 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class, // TODO: Fix tests
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
Expand Down
7 changes: 6 additions & 1 deletion app/Http/Requests/CocktailRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Kami\Cocktail\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Kami\Cocktail\Rules\SubscriberImagesCount;

class CocktailRequest extends FormRequest
{
Expand All @@ -29,7 +30,11 @@ public function rules()
'name' => 'required',
'instructions' => 'required',
'ingredients' => 'array',
'images' => 'array|max:10',
'images' => [
'array',
new SubscriberImagesCount(1, $this->user()),
'max:10',
],
'images.*' => 'integer',
'ingredients.*.ingredient_id' => 'required|integer',
'ingredients.*.units' => 'required_with:ingredients.*.amount',
Expand Down
8 changes: 7 additions & 1 deletion app/Http/Requests/IngredientRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Kami\Cocktail\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Kami\Cocktail\Rules\SubscriberImagesCount;

class IngredientRequest extends FormRequest
{
Expand Down Expand Up @@ -33,7 +34,12 @@ public function rules()
'prices.*.amount' => 'required|numeric|gte:0',
'prices.*.units' => 'required',
'prices.*.price_category_id' => 'int|required',
'images' => 'array|max:1',
'images' => [
'array',
new SubscriberImagesCount(1, $this->user()),
'max:1',
],
'images.*' => 'integer',
];
}
}
2 changes: 1 addition & 1 deletion app/Http/Resources/PriceCategoryResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function toArray($request)
'name' => $this->name,
'description' => $this->description,
'currency' => $this->currency,
'currency_symbol' => $this->getCurrency()->getSymbol(),
'currency_symbol' => '', // TODO:...
];
}
}
2 changes: 1 addition & 1 deletion app/Models/Cocktail.php
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ public function asJsonLDSchema(): array

public function calculatePrice(PriceCategory $priceCategory): Money
{
$totalPrice = Money::of(0, $priceCategory->getCurrency()->value)->toRational();
$totalPrice = Money::of(0, $priceCategory->getCurrency())->toRational();

/** @var CocktailIngredient */
foreach ($this->ingredients as $cocktailIngredient) {
Expand Down
6 changes: 3 additions & 3 deletions app/Models/PriceCategory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Kami\Cocktail\Models;

use Brick\Money\Currency;
use Illuminate\Database\Eloquent\Model;
use PrinsFrank\Standards\Currency\CurrencyAlpha3;
use Kami\Cocktail\Models\Concerns\HasBarAwareScope;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;
Expand All @@ -18,9 +18,9 @@ class PriceCategory extends Model

public $timestamps = false;

public function getCurrency(): CurrencyAlpha3
public function getCurrency(): Currency
{
return CurrencyAlpha3::from($this->currency);
return Currency::of($this->currency);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion app/OpenAPI/Schemas/IngredientPriceRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static function fromArray(array $source): self
$category = PriceCategory::findOrFail((int) $source['price_category_id']);
$price = Money::of(
$source['price'],
$category->getCurrency()->value,
$category->getCurrency(),
roundingMode: RoundingMode::UP
)->getMinorAmount()->toInt();

Expand Down
16 changes: 14 additions & 2 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Kami\Cocktail\Providers;

use Illuminate\Database\Eloquent\Model;
use Throwable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
Expand All @@ -24,6 +26,16 @@ public function register()
*/
public function boot()
{
// Model::preventLazyLoading(!app()->isProduction());
if (DB::getDriverName() === 'sqlite') {
try {
DB::statement('
PRAGMA temp_store = memory;
PRAGMA cache_size = -20000;
PRAGMA mmap_size = 2147483648;
');
} catch (Throwable $e) {
Log::warning('Unable to connect to DB setup PRAGMAs');
}
}
}
}
36 changes: 36 additions & 0 deletions app/Rules/SubscriberImagesCount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Kami\Cocktail\Rules;

use Closure;
use Kami\Cocktail\Models\User;
use Illuminate\Contracts\Validation\ValidationRule;

class SubscriberImagesCount implements ValidationRule
{
public function __construct(private readonly int $maxSubscriberImages, private readonly User $authenticatedUser)
{
}

/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (!config('bar-assistant.enable_billing')) {
return;
}

if ($value && !is_array($value)) {
$value = [$value];
}

$value = (array) $value;

if (!$this->authenticatedUser->hasActiveSubscription() && (count($value) > $this->maxSubscriberImages)) {
$fail('Total images must be less than ' . $this->maxSubscriberImages);
}
}
}
4 changes: 2 additions & 2 deletions app/Rules/ValidCurrency.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Closure;
use Throwable;
use PrinsFrank\Standards\Currency\CurrencyAlpha3;
use Brick\Money\Currency;
use Illuminate\Contracts\Validation\ValidationRule;

class ValidCurrency implements ValidationRule
Expand All @@ -17,7 +17,7 @@ class ValidCurrency implements ValidationRule
public function validate(string $attribute, mixed $value, Closure $fail): void
{
try {
CurrencyAlpha3::from($value);
Currency::of($value);
} catch (Throwable) {
$fail('Currency must be in ISO 4217 (Alpha3) format');
}
Expand Down
2 changes: 1 addition & 1 deletion app/Services/CocktailService.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public function createCocktail(CocktailDTO $cocktailDTO): Cocktail
$imageModels = Image::findOrFail($cocktailDTO->images);
$cocktail->attachImages($imageModels);
} catch (Throwable $e) {
throw new ImagesNotAttachedException();
throw new ImagesNotAttachedException('Unable to attach images to cocktail');
}
}

Expand Down
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"http-interop/http-factory-guzzle": "^1.2",
"jcupitt/vips": "^2.4",
"kalnoy/nestedset": "^6.0",
"karlomikus/recipe-utils": "^0.13.0",
"karlomikus/recipe-utils": "^0.14.0",
"laravel/cashier-paddle": "^2.0",
"laravel/framework": "^11.0",
"laravel/horizon": "^5.21",
Expand All @@ -16,7 +16,6 @@
"laravel/scout": "^10.4",
"league/csv": "^9.0",
"meilisearch/meilisearch-php": "^1.0",
"prinsfrank/standards": "^3.9",
"spatie/array-to-xml": "^3.1",
"spatie/laravel-query-builder": "^5.2",
"spatie/laravel-sluggable": "^3.4",
Expand Down
Loading

0 comments on commit 7f5f5ec

Please sign in to comment.