Skip to content

Commit

Permalink
Merge pull request #397 from karlomikus/develop
Browse files Browse the repository at this point in the history
Minor release
  • Loading branch information
karlomikus authored Jan 1, 2025
2 parents 90169cb + 59ef5c4 commit c21e632
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 136 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
- Added `is_favorited` to cocktail schema
- Added filter by `name` to `/cocktail-methods` endpoint
- Added support for Sentry error reporting via `SENTRY_LARAVEL_DSN` env variable
- Added `bar:migrate-shelf` command for server owners
- Added `org.opencontainers.image.source` label to docker image

## Fixes
- Properties `in_shelf` and `in_bar_shelf` on cocktail schema correctly match substitute and complex ingredients
- Fixed unit parsing for scraping and importing cocktails

# v4.2.7

Ignored, mistake in release protocol

# v4.2.6
## Fixes
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ RUN rm -r .git

FROM serversideup/php:8.3-fpm-nginx AS php-base

LABEL org.opencontainers.image.source="https://github.com/karlomikus/bar-assistant"

ENV S6_CMD_WAIT_FOR_SERVICES=1
ENV APP_BASE_DIR=/var/www/cocktails
ENV NGINX_WEBROOT=/var/www/cocktails/public
Expand Down
72 changes: 72 additions & 0 deletions app/Console/Commands/BarMigrateShelf.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Kami\Cocktail\Console\Commands;

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

class BarMigrateShelf extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'bar:migrate-shelf {barId : Bar ID to specify bar shelf} {userId : User ID of a member in the bar}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Migrate user shelf to bar shelf. User must be a member of the bar';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$barId = (int) $this->argument('barId');
$userId = (int) $this->argument('userId');

$bar = Bar::findOrFail($barId);
$user = User::findOrFail($userId);

$membership = $user->getBarMembership($bar->id);
if ($membership === null) {
$this->error('User is not a member of the specified bar');

return Command::FAILURE;
}

$this->output->block('Migrating user shelf to bar shelf...');

$this->output->writeln('Current bar shelf ingredient count: ' . DB::table('bar_ingredients')->where('bar_id', $barId)->count());
$this->output->writeln('Current user shelf ingredient count: ' . DB::table('user_ingredients')->where('bar_membership_id', $membership->id)->count());

if (!$this->confirm('This will DELETE ALL bar shelf ingredients from selected bar (' . $bar->name . ') and replace them with user shelf ingredients (' . $user->name . '). Continue?')) {
return Command::FAILURE;
}

DB::transaction(function () use ($barId, $userId) {
DB::table('bar_ingredients')->where('bar_id', $barId)->delete();
DB::statement(<<<SQL
INSERT INTO bar_ingredients (bar_id, ingredient_id)
SELECT bar_id, ingredient_id FROM user_ingredients
JOIN bar_memberships ON user_ingredients.bar_membership_id = bar_memberships.id
WHERE user_id = :user_id
AND bar_id = :bar_id
SQL, ['bar_id' => $barId, 'user_id' => $userId]);
});

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

return Command::SUCCESS;
}
}
17 changes: 13 additions & 4 deletions app/Models/ValueObjects/UnitValueObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@

use Stringable;
use JsonSerializable;
use Kami\RecipeUtils\Parser\Parser;
use Kami\RecipeUtils\UnitConverter\Units;

final readonly class UnitValueObject implements Stringable, JsonSerializable
{
public string $value;

/** @var array<string, array<string>> */
public array $units;

public function __construct(
string $value,
?string $value,
) {
$this->value = trim(mb_strtolower($value));
$this->units = (new Parser())->getUnits();
$this->value = trim(mb_strtolower($value ?? ''));
}

public function getAsEnum(): ?Units
Expand All @@ -38,12 +43,16 @@ public function isTopup(): bool

public function isDash(): bool
{
return str_contains($this->value, 'dash') || str_starts_with($this->value, 'drop');
$matches = $this->units['dash'] ?? [];

return in_array($this->value, $matches, true);
}

public function isBarspoon(): bool
{
return str_contains($this->value, 'spoon') || $this->value === 'tsp';
$matches = $this->units['barspoon'] ?? [];

return str_contains($this->value, 'spoon') || in_array($this->value, $matches, true);
}

public function __toString(): string
Expand Down
12 changes: 8 additions & 4 deletions app/Scraper/AbstractSiteExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ public function toArray(): array
];
}, $ingredients);

$image = $this->convertImagesToDataUri();
$images = [];
if ($image['uri']) {
$images[] = $image;
}

$cocktail = Cocktail::fromDraft2Array([
'name' => $this->clean($this->name()),
'instructions' => $this->instructions(),
Expand All @@ -184,9 +190,7 @@ public function toArray(): array
'garnish' => $this->clean($this->garnish()),
'tags' => $this->tags(),
'method' => $this->method(),
'images' => [
$this->convertImagesToDataUri()
],
'images' => $images,
'ingredients' => $ingredients,
]);

Expand Down Expand Up @@ -241,7 +245,7 @@ protected function cleanDescription(?string $description): ?string
private function convertImagesToDataUri(): array
{
$image = $this->image();
if ($image['uri']) {
if ($image['uri'] && !blank($image['uri'])) {
$url = parse_url($image['uri']);
$cleanUrl = ($url['scheme'] ?? '') . '://' . ($url['host'] ?? '') . (isset($url['path']) ? $url['path'] : '');

Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/CocktailsDistilled.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function ingredients(): array
$amount = (int) str_replace('ml', '', $measureMl);
$units = 'ml';
} else {
$recipeIngredient = $this->ingredientParser->parseLine($measureMl, $this->defaultConvertTo, [Units::Dash]);
$recipeIngredient = $this->ingredientParser->parseLine($measureMl, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
$amount = $recipeIngredient->amount;
$units = $recipeIngredient->units;
}
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/DefaultScraper.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public function ingredients(): array
foreach ($ingredients as $ingredient) {
$ingredient = html_entity_decode($ingredient, ENT_SUBSTITUTE | ENT_HTML5); // Convert entities to correct chars
$ingredient = e(trim($ingredient, " \n\r\t\v\x00\"\'"));
$recipeIngredient = $this->ingredientParser->parseLine($ingredient, $this->defaultConvertTo, [Units::Dash]);
$recipeIngredient = $this->ingredientParser->parseLine($ingredient, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);

if (empty($recipeIngredient->amount) || empty($recipeIngredient->name) || empty($recipeIngredient->units)) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/EricsCocktailGuide.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function ingredients(): array
{
$result = [];
$this->crawler->filterXPath("//ol[contains(@class, 'recipe_recipeIngredients__')]")->filter('li')->each(function ($node) use (&$result) {
$result[] = $this->ingredientParser->parseLine($node->text(), $this->defaultConvertTo, [Units::Dash]);
$result[] = $this->ingredientParser->parseLine($node->text(), $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
});

return $result;
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/HausAlpenz.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function ingredients(): array
{
$result = [];
$this->crawler->filter("p.measure")->each(function ($node) use (&$result) {
$result[] = $this->ingredientParser->parseLine($node->text(), $this->defaultConvertTo, [Units::Dash]);
$result[] = $this->ingredientParser->parseLine($node->text(), $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
});

return $result;
Expand Down
4 changes: 2 additions & 2 deletions app/Scraper/Sites/ImbibeMagazine.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ public function ingredients(): array
$schemaIngredients = $this->getRecipeSchema()['recipeIngredient'] ?? [];

foreach ($schemaIngredients as $ingredient) {
$result[] = $this->ingredientParser->parseLine($ingredient['ingredient'], $this->defaultConvertTo, [Units::Dash]);
$result[] = $this->ingredientParser->parseLine($ingredient['ingredient'], $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
}

if (empty($result)) {
foreach ($this->getLegacyRecipeIngredients() as $line) {
if (str_starts_with($line, 'Tools:') || str_starts_with($line, 'Garnish:') || str_starts_with($line, 'Glass:')) {
continue;
}
$result[] = $this->ingredientParser->parseLine($line, $this->defaultConvertTo, [Units::Dash]);
$result[] = $this->ingredientParser->parseLine($line, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
}
}

Expand Down
12 changes: 11 additions & 1 deletion app/Scraper/Sites/KindredCocktails.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Kami\Cocktail\Scraper\Sites;

use Exception;
use Throwable;
use Kami\RecipeUtils\UnitConverter\Units;
use Symfony\Component\DomCrawler\Crawler;
Expand Down Expand Up @@ -54,7 +55,7 @@ public function ingredients(): array
$ingredientString = $node->text();

if (!str_contains($ingredientString, 'as garnish')) {
$result[] = $this->ingredientParser->parseLine($ingredientString, $this->defaultConvertTo, [Units::Dash]);
$result[] = $this->ingredientParser->parseLine($ingredientString, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
}
});

Expand All @@ -70,6 +71,11 @@ public function image(): ?array

try {
$result['uri'] = $this->crawler->filterXPath('//img[@property="schema:image"]')->first()->attr('src');

if (blank($result['uri'])) {
throw new Exception('No image found');
}

if (!str_starts_with($result['uri'], 'http')) {
$result['uri'] = 'https://kindredcocktails.com' . $result['uri'];
}
Expand All @@ -78,6 +84,10 @@ public function image(): ?array

try {
$result['copyright'] = trim($this->crawler->filter('figcaption.caption')->first()->text());

if (blank($result['copyright'])) {
throw new Exception('No copyright found');
}
} catch (Throwable) {
}

Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/LiberAndCo.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function ingredients(): array
$this->crawler->filterXPath('//p/strong[contains(text(), \'Ingredients:\')]/following::ul')->first()->filter('li')->each(function ($node) use (&$result) {
$ingredientString = $node->text();

$recipeIngredient = $this->ingredientParser->parseLine($ingredientString, $this->defaultConvertTo, [Units::Dash]);
$recipeIngredient = $this->ingredientParser->parseLine($ingredientString, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);

$amount = $recipeIngredient->amount;
if ($amount === 0.0) {
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/LiquorCom.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function ingredients(): array
$ingredients = [];

foreach ($this->getRecipeSchema()['recipeIngredient'] as $sourceIngredient) {
$ingredients[] = $this->ingredientParser->parseLine($sourceIngredient, $this->defaultConvertTo, [Units::Dash]);
$ingredients[] = $this->ingredientParser->parseLine($sourceIngredient, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
}

return $ingredients;
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/SteveTheBartender.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function ingredients(): array
$ingredients = $this->getRecipeSchema()['recipeIngredient'];

foreach ($ingredients as $ingredient) {
$result[] = $this->ingredientParser->parseLine($ingredient, $this->defaultConvertTo, [Units::Dash]);
$result[] = $this->ingredientParser->parseLine($ingredient, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);
}

return $result;
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/TheCocktailDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function ingredients(): array
break;
}

$recipeIngredient = $this->ingredientParser->parseLine($this->apiDrinkData[$measureKey], $this->defaultConvertTo, [Units::Dash]);
$recipeIngredient = $this->ingredientParser->parseLine($this->apiDrinkData[$measureKey], $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);

$result[] = new RecipeIngredient(
$this->apiDrinkData[$ingKey],
Expand Down
2 changes: 1 addition & 1 deletion app/Scraper/Sites/TuxedoNo2.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function ingredients(): array
}

$amountAndUnits = $node->filter('.amount')->text();
$recipeIngredient = $this->ingredientParser->parseLine(str_replace($onlyUnits, '', $amountAndUnits) . ' ' . $onlyUnits, $this->defaultConvertTo, [Units::Dash]);
$recipeIngredient = $this->ingredientParser->parseLine(str_replace($onlyUnits, '', $amountAndUnits) . ' ' . $onlyUnits, $this->defaultConvertTo, [Units::Dash, Units::Barspoon]);

if ($node->filter('.ingredient a')->count() === 0) {
return;
Expand Down
Loading

0 comments on commit c21e632

Please sign in to comment.