Skip to content

Commit

Permalink
Merge pull request #28 from karlomikus/develop
Browse files Browse the repository at this point in the history
Merge v101
  • Loading branch information
karlomikus committed Dec 3, 2022
2 parents 30909e5 + 3727f30 commit 778079b
Show file tree
Hide file tree
Showing 30 changed files with 1,140 additions and 725 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ npm-debug.log
yarn-error.log
/.idea
/.vscode
docker-compose.yml
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# v1.0.1
## New
- Make cocktail `id` attribute filterable in cocktails index
- Add `per_page` query parameter to cocktails endpoint (defaults to 15)
- Add profile update endpoint
- Search index settings are updated on docker restart

## Fixes
- Sort shelf cocktails by name
- Document missing query parameters in OA specification

# v1.0.0
- Cover all endpoints with tests
- Add coding style
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The basic requirements are:

- PHP >= 8.1
- Sqlite 3
- Working [Meilisearch server](https://github.com/meilisearch) instance
- Working [Meilisearch server](https://github.com/meilisearch) instance (v0.29)
- (Optional) Redis server instance

## Docker setup
Expand Down
107 changes: 107 additions & 0 deletions app/Console/Commands/BarScrape.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

namespace Kami\Cocktail\Console\Commands;

use Illuminate\Support\Str;
use Illuminate\Console\Command;
use Kami\Cocktail\Models\Glass;
use Kami\Cocktail\Models\Image;
use Illuminate\Support\Facades\DB;
use Kami\Cocktail\Scraper\Manager;
use Kami\Cocktail\Services\CocktailService;
use Kami\Cocktail\Services\IngredientService;
use Intervention\Image\ImageManagerStatic as InterventionImage;

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

/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$scraper = Manager::scrape($this->argument('url'));

$scrapedData = $scraper->toArray();

/** @var IngredientService */
$ingredientService = app(IngredientService::class);
/** @var CocktailService */
$cocktailService = app(CocktailService::class);

$dbIngredients = DB::table('ingredients')->select('id', DB::raw('LOWER(name) AS name'))->get()->keyBy('name');
$dbGlasses = DB::table('glasses')->select('id', DB::raw('LOWER(name) AS name'))->get()->keyBy('name');

$cocktailImages = [];
if ($scrapedData['image']['url']) {
$memImage = InterventionImage::make($scrapedData['image']['url']);

$filepath = 'temp/' . Str::random(40) . '.jpg';
$memImage->save(storage_path('uploads/' . $filepath));

$image = new Image();
$image->copyright = $scrapedData['image']['copyright'] ?? null;
$image->file_path = $filepath;
$image->file_extension = 'jpg';
$image->save();

$cocktailImages[] = $image->id;
}

// Match ingredients
foreach ($scrapedData['ingredients'] as &$scrapedIngredient) {
if ($dbIngredients->has(strtolower($scrapedIngredient['name']))) {
$scrapedIngredient['ingredient_id'] = $dbIngredients->get(strtolower($scrapedIngredient['name']))->id;
} else {
$this->info('Creating a new ingredient: ' . $scrapedIngredient['name']);
$newIngredient = $ingredientService->createIngredient(ucfirst($scrapedIngredient['name']), 1, 1, description: 'Created by scraper from ' . $scrapedData['source']);
$dbIngredients->put(strtolower($scrapedIngredient['name']), $newIngredient->id);
$scrapedIngredient['ingredient_id'] = $newIngredient->id;
}
}

// Match glass
$glassId = null;
if ($dbGlasses->has(strtolower($scrapedData['glass']))) {
$glassId = $dbGlasses->get(strtolower($scrapedData['glass']))->id;
} elseif ($scrapedData['glass'] !== null) {
$this->info('Creating a new glass type: ' . $scrapedData['glass']);
$newGlass = new Glass();
$newGlass->name = ucfirst($scrapedData['glass']);
$newGlass->description = 'Created by scraper from ' . $scrapedData['source'];
$newGlass->save();
$dbGlasses->put(strtolower($scrapedData['glass']), $newGlass->id);
$glassId = $newGlass->id;
}

$cocktailService->createCocktail(
$scrapedData['name'],
$scrapedData['instructions'],
$scrapedData['ingredients'],
1,
$scrapedData['description'],
$scrapedData['garnish'],
$scrapedData['source'],
$cocktailImages,
$scrapedData['tags'],
$glassId
);

return Command::SUCCESS;
}
}
14 changes: 7 additions & 7 deletions app/Console/Commands/BarSearchRefresh.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ public function handle()
{
// Clear indexes
// SearchActions::flushSearchIndex(); // TODO: Create method to import site_index
$this->info('Removing cocktails and ingredients index...');
Artisan::call('scout:flush', ['model' => "Kami\Cocktail\Models\Cocktail"]);
Artisan::call('scout:flush', ['model' => "Kami\Cocktail\Models\Ingredient"]);
// $this->info('Removing cocktails and ingredients index...');
// Artisan::call('scout:flush', ['model' => "Kami\Cocktail\Models\Cocktail"]);
// Artisan::call('scout:flush', ['model' => "Kami\Cocktail\Models\Ingredient"]);

// Update settings
$this->info('Updating index settings...');
$this->info('Updating search index settings...');
SearchActions::updateIndexSettings();

$this->info('Importing cocktails and ingredients...');
Artisan::call('scout:import', ['model' => "Kami\Cocktail\Models\Cocktail"]);
Artisan::call('scout:import', ['model' => "Kami\Cocktail\Models\Ingredient"]);
// $this->info('Importing cocktails and ingredients...');
// Artisan::call('scout:import', ['model' => "Kami\Cocktail\Models\Cocktail"]);
// Artisan::call('scout:import', ['model' => "Kami\Cocktail\Models\Ingredient"]);

return Command::SUCCESS;
}
Expand Down
41 changes: 0 additions & 41 deletions app/Console/Commands/TestScrap.php

This file was deleted.

11 changes: 11 additions & 0 deletions app/Exceptions/ScrapeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Kami\Cocktail\Exceptions;

use Exception;

class ScrapeException extends Exception
{
}
8 changes: 5 additions & 3 deletions app/Http/Controllers/CocktailController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ class CocktailController extends Controller
{
/**
* List all cocktails
* - Paginated by 15 items
* - Paginated by X items
* Optional query strings:
* - user_id -> Filter by user id
* - favorites -> Filter by user favorites
*/
public function index(Request $request): JsonResource
{
$cocktails = Cocktail::with('ingredients.ingredient', 'images', 'tags');
$cocktails = Cocktail::with('ingredients.ingredient', 'images', 'tags')->orderBy('name');

$perPage = $request->get('per_page', 15);

if ($request->has('user_id')) {
$cocktails->where('user_id', $request->get('user_id'));
Expand All @@ -38,7 +40,7 @@ public function index(Request $request): JsonResource
});
}

return CocktailResource::collection($cocktails->paginate(15));
return CocktailResource::collection($cocktails->paginate($perPage));
}

/**
Expand Down
5 changes: 4 additions & 1 deletion app/Http/Controllers/ShelfController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ class ShelfController extends Controller
{
public function index(Request $request): JsonResource
{
$userIngredients = $request->user()->shelfIngredients;
$userIngredients = $request->user()
->shelfIngredients
->sortBy('ingredient.name')
->load('ingredient');

return UserIngredientResource::collection($userIngredients);
}
Expand Down
19 changes: 19 additions & 0 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace Kami\Cocktail\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Kami\Cocktail\Http\Resources\UserResource;
use Illuminate\Http\Resources\Json\JsonResource;
use Kami\Cocktail\Http\Requests\UpdateUserRequest;

class UserController extends Controller
{
Expand All @@ -16,4 +18,21 @@ public function show(Request $request): JsonResource
$request->user()->load('favorites', 'shelfIngredients', 'shoppingLists')
);
}

public function update(UpdateUserRequest $request): JsonResource
{
$currentUser = $request->user();
$currentUser->name = $request->post('name');
$currentUser->email = $request->post('email');

if ($request->has('password')) {
$currentUser->password = Hash::make($request->post('password'));
}

$currentUser->save();

return new UserResource(
$request->user()->load('favorites', 'shelfIngredients', 'shoppingLists')
);
}
}
35 changes: 35 additions & 0 deletions app/Http/Requests/UpdateUserRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Kami\Cocktail\Http\Requests;

use Illuminate\Validation\Rule;
use Illuminate\Foundation\Http\FormRequest;

class UpdateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'email' => ['required', Rule::unique('users')->ignore($this->user()->id)],
'name' => 'required',
'password' => 'confirmed|nullable',
];
}
}
6 changes: 6 additions & 0 deletions app/Models/UserIngredient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
namespace Kami\Cocktail\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class UserIngredient extends Model
{
use HasFactory;

public $timestamps = false;

public function ingredient(): BelongsTo
{
return $this->belongsTo(Ingredient::class);
}
}
Loading

0 comments on commit 778079b

Please sign in to comment.