Skip to content

Commit

Permalink
add name and meta fields to reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
repl6669 committed Jan 13, 2024
1 parent 3d27040 commit a394db5
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 31 deletions.
1 change: 1 addition & 0 deletions config/reviews.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
'settings' => [
'include_unpublished_auth_user_reviews' => true,
'auth_required' => true,
'name_required' => false,
'auth_middleware' => ['auth'],
],
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Lunar\Base\Migration;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table($this->prefix.'reviews', function (Blueprint $table) {
$table->string('name')->nullable()->after('user_id');
$table->json('meta')->nullable()->after('comment');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table($this->prefix.'reviews', function (Blueprint $table) {
$table->dropColumn('name');
$table->dropColumn('meta');
});
}
};
5 changes: 5 additions & 0 deletions lang/en/validations.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
'max' => 'Rating may not be greater than 5.',
],

'name' => [
'required' => 'Please enter your name.',
'string' => 'Name must be a string.',
],

'comment' => [
'string' => 'Comment must be a string.',
],
Expand Down
3 changes: 2 additions & 1 deletion src/Domain/Hub/Components/Slots/ReviewsSlot.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Dystcz\LunarApiReviews\Domain\Hub\Components\Slots;

use Carbon\Carbon;
use Dystcz\LunarApiReviews\Domain\Reviews\Models\Review;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
Expand Down Expand Up @@ -50,7 +51,7 @@ public function handleSlotSave($model, $data): void

public function toggle(Review $review): void
{
$review->update(['published_at' => $review->published_at ? null : now()]);
$review->update(['published_at' => $review->published_at ? null : Carbon::now()]);

$this->setPage($this->page);
}
Expand Down
4 changes: 4 additions & 0 deletions src/Domain/Reviews/Factories/ReviewFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ public function definition(): array
return [
'user_id' => User::factory(),
'rating' => $this->faker->numberBetween(1, 5),
'name' => $this->faker->name,
'comment' => $this->faker->text(100),
'meta' => [
'foo' => 'bar',
],
];
}
}
2 changes: 1 addition & 1 deletion src/Domain/Reviews/Http/Routing/ReviewRouteGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ReviewRouteGroup extends RouteGroup
/**
* Register routes.
*/
public function routes(string $prefix = null, array|string $middleware = []): void
public function routes(?string $prefix = null, array|string $middleware = []): void
{
JsonApiRoute::server('v1')
->prefix('v1')
Expand Down
37 changes: 27 additions & 10 deletions src/Domain/Reviews/JsonApi/V1/ReviewRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Dystcz\LunarApiReviews\Domain\Reviews\JsonApi\V1;

use Illuminate\Support\Facades\Config;
use LaravelJsonApi\Laravel\Http\Requests\ResourceRequest;
use LaravelJsonApi\Validation\Rule as JsonApiRule;

Expand All @@ -14,17 +15,25 @@ class ReviewRequest extends ResourceRequest
*/
public function rules(): array
{
return [
$rules = [
'rating' => [
'required',
'integer',
'min:1',
'max:5',
],
'name' => [
'nullable',
'string',
],
'comment' => [
'nullable',
'string',
],
'meta' => [
'nullable',
'array',
],
'purchasable_id' => [
'required',
'integer',
Expand All @@ -38,6 +47,12 @@ public function rules(): array
JsonApiRule::dateTime(),
],
];

if (Config::get('lunar-api.reviews.domains.reviews.settings.name_required', false)) {
$rules['name'] = ['required', ...$rules['name']];
}

return $rules;
}

/**
Expand All @@ -48,15 +63,17 @@ public function rules(): array
public function messages(): array
{
return [
'rating.required' => __('lunar-api-reviews::validations.store_product_notification.rating.required'),
'rating.integer' => __('lunar-api-reviews::validations.store_product_notification.rating.integer'),
'rating.min' => __('lunar-api-reviews::validations.store_product_notification.rating.min'),
'rating.max' => __('lunar-api-reviews::validations.store_product_notification.rating.max'),
'comment.string' => __('lunar-api-reviews::validations.store_product_notification.comment.string'),
'purchasable_id.required' => __('lunar-api-reviews::validations.store_product_notification.purchasable_id.required'),
'purchasable_id.integer' => __('lunar-api-reviews::validations.store_product_notification.purchasable_id.integer'),
'purchasable_type.required' => __('lunar-api-reviews::validations.store_product_notification.purchasable_type.required'),
'purchasable_type.string' => __('lunar-api-reviews::validations.store_product_notification.purchasable_type.string'),
'rating.required' => __('lunar-api-reviews::validations.rating.required'),
'rating.integer' => __('lunar-api-reviews::validations.rating.integer'),
'rating.min' => __('lunar-api-reviews::validations.rating.min'),
'rating.max' => __('lunar-api-reviews::validations.rating.max'),
'name.required' => __('lunar-api-reviews::validations.name.required'),
'name.string' => __('lunar-api-reviews::validations.name.string'),
'comment.string' => __('lunar-api-reviews::validations.comment.string'),
'purchasable_id.required' => __('lunar-api-reviews::validations.purchasable_id.required'),
'purchasable_id.integer' => __('lunar-api-reviews::validations.surchasable_id.integer'),
'purchasable_type.required' => __('lunar-api-reviews::validations.purchasable_type.required'),
'purchasable_type.string' => __('lunar-api-reviews::validations.strchasable_type.string'),
];
}
}
11 changes: 7 additions & 4 deletions src/Domain/Reviews/JsonApi/V1/ReviewSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
use Dystcz\LunarApiReviews\Domain\Reviews\Models\Review;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use LaravelJsonApi\Eloquent\Fields\ArrayHash;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Number;
use LaravelJsonApi\Eloquent\Fields\Relations\BelongsTo;
use LaravelJsonApi\Eloquent\Fields\Relations\MorphTo;
Expand Down Expand Up @@ -65,21 +65,24 @@ public function indexQuery(?Request $request, Builder $query): Builder
public function fields(): iterable
{
return [
ID::make(),
$this->idField(),

Str::make('name')
->extractUsing(
fn ($model, $column, $value) => $model->user?->customers->first()?->name ?? $value,
fn ($model, $column, $value) => $model->name,
),

Str::make('comment'),

Number::make('rating')->sortable(),
Number::make('rating')
->sortable(),

Number::make('purchasable_id'),

Str::make('purchasable_type'),

ArrayHash::make('meta'),

DateTime::make('published_at')
->serializeUsing(
static fn ($value) => $value?->format('Y-m-d H:i:s'),
Expand Down
27 changes: 19 additions & 8 deletions src/Domain/Reviews/Models/Review.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Dystcz\LunarApiReviews\Domain\Reviews\Builders\ReviewBuilder;
use Dystcz\LunarApiReviews\Domain\Reviews\Factories\ReviewFactory;
use Dystcz\LunarApiReviews\Domain\Reviews\Scopes\PublishedScope;
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
Expand All @@ -18,16 +20,15 @@ class Review extends BaseModel
{
use HasFactory;

protected $fillable = [
'rating',
'comment',
'published_at',
'user_id',
'purchasable_id',
'purchasable_type',
];
protected $guarded = [];

/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'meta' => AsArrayObject::class,
'published_at' => 'datetime',
];

Expand Down Expand Up @@ -58,6 +59,16 @@ protected static function newFactory(): ReviewFactory
return ReviewFactory::new();
}

/**
* Get the name attribute.
*/
public function name(): Attribute
{
return Attribute::make(
get: fn (?string $value) => $this->user?->customers->first()?->name ?? $value,
);
}

/**
* Purchasable relation.
*/
Expand Down
7 changes: 4 additions & 3 deletions src/LunarReviewsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Dystcz\LunarApi\Domain\ProductVariants\JsonApi\V1\ProductVariantResource;
use Dystcz\LunarApi\Domain\ProductVariants\JsonApi\V1\ProductVariantSchema;
use Dystcz\LunarApi\Support\Config\Collections\DomainConfigCollection;
use Dystcz\LunarApiReviews\Domain\Hub\Components\Slots\ReviewsSlot;
use Dystcz\LunarApiReviews\Domain\Reviews\JsonApi\V1\ReviewSchema;
use Dystcz\LunarApiReviews\Domain\Reviews\Models\Review;
use Dystcz\LunarApiReviews\Domain\Reviews\Observers\ReviewObserver;
Expand Down Expand Up @@ -63,15 +64,15 @@ public function boot(): void

Livewire::component(
'lunar-api-reviews::reviews-slot',
\Dystcz\LunarApiReviews\Domain\Hub\Components\Slots\ReviewsSlot::class,
ReviewsSlot::class,
);

Slot::register(
'product.show',
\Dystcz\LunarApiReviews\Domain\Hub\Components\Slots\ReviewsSlot::class,
ReviewsSlot::class,
);

\Dystcz\LunarApiReviews\Domain\Reviews\Models\Review::observe(ReviewObserver::class);
Review::observe(ReviewObserver::class);

if ($this->app->runningInConsole()) {
$this->publishConfig();
Expand Down
87 changes: 83 additions & 4 deletions tests/Feature/CanCreateReviewsForPurchasableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,86 @@
'status' => '401',
'title' => 'Unauthorized',
]);
});
})->group('reviews');

it('can save a review with name and meta', function () {
/** @var TestCase $this */

/** @var User $user */
$user = UserFactory::new()->create();

/** @var Review $review */
$review = Review::factory()
->for(Product::factory(), 'purchasable')
->make();

$data = [
'type' => 'reviews',
'attributes' => [
'comment' => $review->comment,
'rating' => $review->rating,
'name' => $review->name,
'purchasable_id' => $review->purchasable_id,
'purchasable_type' => $review->purchasable_type,
'meta' => $review->meta,
],
];

$response = $this
->actingAs($user)
->jsonApi()
->expects('reviews')
->withData($data)
->post('/api/v1/reviews');

$id = $response
->assertCreatedWithServerId('http://localhost/api/v1/reviews', $data)
->id();

$this->assertDatabaseHas($review->getTable(), [
'id' => $id,
'user_id' => $user->id,
'purchasable_id' => $review->purchasable_id,
'purchasable_type' => $review->purchasable_type,
'comment' => $review->comment,
'rating' => $review->rating,
'name' => $review->name,
'meta' => json_encode($review->meta),
]);
})->group('reviews');

it('requires a rating and comment, but also a name in order to be saved', function () {

/** @var TestCase $this */
Config::set('lunar-api.reviews.domains.reviews.settings.name_required', true);

$product = Product::factory()->create();

/** @var User $user */
$user = UserFactory::new()->create();

$data = [
'type' => 'reviews',
'attributes' => [
'purchasable_id' => $product->id,
'purchasable_type' => $product->getMorphClass(),
],
];

$response = $this
->actingAs($user)
->jsonApi()
->expects('reviews')
->withData($data)
->post('/api/v1/reviews');

$response
->assertErrors(422, [
['detail' => __('lunar-api-reviews::validations.rating.required'), 'status' => '422'],
['detail' => __('lunar-api-reviews::validations.name.required'), 'status' => '422'],
]);

})->group('reviews');

it('can store anonymous review when configured', function () {
/** @var TestCase $this */
Expand Down Expand Up @@ -79,7 +158,7 @@
'comment' => $review->comment,
'rating' => $review->rating,
]);
})->todo();
})->todo()->group('reviews');

it('can create a review for a product', function () {
/** @var TestCase $this */
Expand Down Expand Up @@ -121,7 +200,7 @@
'comment' => $review->comment,
'rating' => $review->rating,
]);
});
})->group('reviews');

it('can create a review for a product variant', function () {
/** @var TestCase $this */
Expand Down Expand Up @@ -163,4 +242,4 @@
'comment' => $review->comment,
'rating' => $review->rating,
]);
});
})->group('reviews');

0 comments on commit a394db5

Please sign in to comment.