Skip to content

Commit

Permalink
Improve images count validation
Browse files Browse the repository at this point in the history
  • Loading branch information
karlomikus committed Dec 11, 2024
1 parent 6e79822 commit 81626fc
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 3 deletions.
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',
];
}
}
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);
}
}
}
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
21 changes: 21 additions & 0 deletions tests/Feature/Http/BarControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Kami\Cocktail\Models\Bar;
use Kami\Cocktail\Models\User;
use Kami\Cocktail\Models\Image;
use Illuminate\Support\Facades\Config;
use Kami\Cocktail\Models\Enums\UserRoleEnum;
use Illuminate\Foundation\Testing\RefreshDatabase;

Expand Down Expand Up @@ -206,4 +207,24 @@ public function test_join_bar_with_invite_code(): void
$response->assertOk();
$this->assertSame(1, $bar->memberships()->count());
}

public function test_limits_bar_count_for_unsubscribed_users(): void
{
Config::set('bar-assistant.enable_billing', true);

$user = User::factory()->create();
$this->actingAs($user);

$response = $this->postJson('/api/bars', [
'name' => 'Test bar name'
]);

$response->assertCreated();

$response = $this->postJson('/api/bars', [
'name' => 'Test bar name'
]);

$response->assertForbidden();
}
}
77 changes: 77 additions & 0 deletions tests/Feature/Http/CocktailControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
use Kami\Cocktail\Models\User;
use Kami\Cocktail\Models\Glass;
use Kami\Cocktail\Models\Image;
use Laravel\Paddle\Subscription;
use Illuminate\Http\UploadedFile;
use Kami\Cocktail\Models\Utensil;
use Kami\Cocktail\Models\Cocktail;
use Kami\Cocktail\Models\Ingredient;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage;
use Kami\Cocktail\Models\PriceCategory;
use Kami\Cocktail\Models\CocktailMethod;
Expand All @@ -31,6 +33,8 @@ public function setUp(): void
{
parent::setUp();

Config::set('bar-assistant.enable_billing', false);

$this->actingAs(
User::factory()->create()
);
Expand Down Expand Up @@ -791,4 +795,77 @@ public function test_cocktail_prices(): void
$response->assertJsonPath('data.0.prices_per_ingredient.2.price_per_use.price', 0.4);
$response->assertJsonPath('data.0.total_price.price', 2);
}

public function test_max_images_validation(): void
{
$membership = $this->setupBarMembership();
$this->actingAs($membership->user);

$this->withHeader('Bar-Assistant-Bar-Id', (string) $membership->bar_id);

$images = Image::factory()->count(11)->create();

$response = $this->postJson('/api/cocktails', [
'name' => "Cocktail name",
'instructions' => "1. Step\n2. Step",
'description' => "Cocktail description",
'images' => $images->pluck('id')->toArray(),
]);
$response->assertUnprocessable();

$response = $this->postJson('/api/cocktails', [
'name' => "Cocktail name",
'instructions' => "1. Step\n2. Step",
'description' => "Cocktail description",
'images' => $images->take(10)->pluck('id')->toArray(),
]);
$response->assertCreated();
}

public function test_limits_cocktails_images_limit_for_unsubscribed_users(): void
{
Config::set('bar-assistant.enable_billing', true);

$membership = $this->setupBarMembership();
$this->actingAs($membership->user);

$this->withHeader('Bar-Assistant-Bar-Id', (string) $membership->bar_id);

$image1 = Image::factory()->create();
$image2 = Image::factory()->create();
$image3 = Image::factory()->create();

$response = $this->postJson('/api/cocktails', [
'name' => "Cocktail name",
'instructions' => "1. Step\n2. Step",
'description' => "Cocktail description",
'images' => [$image1->id, $image2->id, $image3->id],
]);

$response->assertUnprocessable();

$response = $this->postJson('/api/cocktails', [
'name' => "Cocktail name",
'instructions' => "1. Step\n2. Step",
'description' => "Cocktail description",
'images' => [$image1->id],
]);

$response->assertCreated();

$membership->user->subscriptions()->create([
'type' => 'default',
'paddle_id' => 'sub_12345',
'status' => Subscription::STATUS_ACTIVE,
]);
$membership->user->refresh();

$response = $this->postJson('/api/cocktails', [
'name' => "Cocktail name",
'instructions' => "1. Step\n2. Step",
'description' => "Cocktail description",
'images' => [$image1->id, $image2->id, $image3->id],
]);
$response->assertCreated();
}
}

0 comments on commit 81626fc

Please sign in to comment.