Merge pull request 'feature: add api for categories, docker build and compose for development mode' (#11) from feat/add-container-build into dev
Reviewed-on: https://codeberg.org/headshed/share-lt/pulls/11
This commit is contained in:
commit
224654cabf
14 changed files with 520 additions and 0 deletions
28
.dockerignore
Normal file
28
.dockerignore
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Ignore .env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# Ignore node_modules
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Ignore vendor folder
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# Ignore log files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Ignore IDE and editor files
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Ignore system files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Ignore Laravel storage
|
||||||
|
/storage/*.key
|
||||||
|
/storage/*.log
|
||||||
|
/storage/framework/cache/*
|
||||||
|
/storage/framework/sessions/*
|
||||||
|
/storage/framework/views/*
|
||||||
|
/storage/logs/*
|
||||||
89
Dockerfile
Normal file
89
Dockerfile
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
FROM php:8.5-fpm-alpine
|
||||||
|
|
||||||
|
# Copy composer.lock and composer.json
|
||||||
|
COPY composer.lock composer.json /var/www/
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /var/www
|
||||||
|
|
||||||
|
# # Install dependencies
|
||||||
|
RUN apk update && apk add --no-cache \
|
||||||
|
build-base \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
freetype-dev \
|
||||||
|
zip \
|
||||||
|
jpegoptim optipng pngquant gifsicle \
|
||||||
|
vim \
|
||||||
|
unzip \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
libzip-dev \
|
||||||
|
oniguruma-dev \
|
||||||
|
icu-dev \
|
||||||
|
sqlite \
|
||||||
|
sqlite-dev \
|
||||||
|
nodejs \
|
||||||
|
npm
|
||||||
|
|
||||||
|
|
||||||
|
# # Clear cache
|
||||||
|
RUN rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
# # Install extensions
|
||||||
|
RUN docker-php-ext-install mbstring zip exif pcntl intl pdo_sqlite
|
||||||
|
|
||||||
|
RUN docker-php-ext-install gd
|
||||||
|
|
||||||
|
# # Install composer
|
||||||
|
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||||
|
|
||||||
|
# Add user for laravel application
|
||||||
|
RUN addgroup -g 1000 www
|
||||||
|
RUN adduser -u 1000 -G www -s /bin/sh -D www
|
||||||
|
|
||||||
|
# # Copy existing application directory contents
|
||||||
|
COPY . /var/www
|
||||||
|
|
||||||
|
# # Copy existing application directory permissions
|
||||||
|
COPY --chown=www-data:www-data . /var/www
|
||||||
|
|
||||||
|
# # Install PHP dependencies
|
||||||
|
RUN composer install --no-dev --optimize-autoloader
|
||||||
|
|
||||||
|
# Install Node.js dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Build assets
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Change ownership of /var/www to www-data
|
||||||
|
RUN chmod -R u+rw /var/www && chown -R www:www /var/www
|
||||||
|
|
||||||
|
# # RUN php artisan optimize
|
||||||
|
# # removed as it calls all 4 commands below and fails du to
|
||||||
|
# # multi-site configuration
|
||||||
|
|
||||||
|
# # Clear any cached configurations
|
||||||
|
RUN php artisan config:clear
|
||||||
|
# RUN php artisan cache:clear
|
||||||
|
RUN php artisan route:clear
|
||||||
|
RUN php artisan view:clear
|
||||||
|
|
||||||
|
# # Build optimizations
|
||||||
|
RUN php artisan config:cache
|
||||||
|
RUN php artisan event:cache
|
||||||
|
RUN php artisan view:cache
|
||||||
|
|
||||||
|
# # RUN php artisan route:cache
|
||||||
|
|
||||||
|
# # Run Laravel artisan command
|
||||||
|
RUN php artisan storage:link
|
||||||
|
|
||||||
|
# # RUN composer install --optimize-autoloader --no-dev
|
||||||
|
|
||||||
|
# # Change current user to www
|
||||||
|
USER www
|
||||||
|
|
||||||
|
# # Expose port 9000 and start php-fpm server
|
||||||
|
# EXPOSE 9000
|
||||||
61
app/Http/Controllers/CategoryController.php
Normal file
61
app/Http/Controllers/CategoryController.php
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\StoreCategoryRequest;
|
||||||
|
use App\Http\Requests\UpdateCategoryRequest;
|
||||||
|
use App\Http\Resources\CategoryResource;
|
||||||
|
use App\Models\Category;
|
||||||
|
|
||||||
|
class CategoryController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return CategoryResource::collection(Category::all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(StoreCategoryRequest $request)
|
||||||
|
{
|
||||||
|
return new CategoryResource(Category::create($request->validated()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(Category $category)
|
||||||
|
{
|
||||||
|
return new CategoryResource($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdateCategoryRequest $request, Category $category)
|
||||||
|
{
|
||||||
|
$category->update($request->validated());
|
||||||
|
|
||||||
|
return new CategoryResource($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Category $category)
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (! $user || $user->email !== config('app.admin_email')) {
|
||||||
|
return response()->json(['message' => 'Forbidden'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$category->delete();
|
||||||
|
|
||||||
|
return response()->noContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Requests/StoreCategoryRequest.php
Normal file
28
app/Http/Requests/StoreCategoryRequest.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreCategoryRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return $this->user() && $this->user()->email === config('app.admin_email');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|max:255|unique:categories,name',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Requests/UpdateCategoryRequest.php
Normal file
28
app/Http/Requests/UpdateCategoryRequest.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateCategoryRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return $this->user() && $this->user()->email === config('app.admin_email');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'sometimes|required|string|max:255|unique:categories,name,'.$this->category->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Http/Resources/CategoryResource.php
Normal file
24
app/Http/Resources/CategoryResource.php
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class CategoryResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'name' => $this->name,
|
||||||
|
'created_at' => $this->created_at,
|
||||||
|
'updated_at' => $this->updated_at,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,12 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Category extends Model
|
class Category extends Model
|
||||||
{
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
protected $fillable = ['name'];
|
protected $fillable = ['name'];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
cmd/build_container.sh
Executable file
11
cmd/build_container.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
LARAVEL_CONTAINER_NAME="quay.io/marshyon/share-lt"
|
||||||
|
CONTAINER_LABEL="0.0.1"
|
||||||
|
CACHE="--no-cache"
|
||||||
|
CACHE=""
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
$CACHE \
|
||||||
|
-t ${LARAVEL_CONTAINER_NAME}:${CONTAINER_LABEL} \
|
||||||
|
-f Dockerfile .
|
||||||
15
cmd/curl_get_categories.sh
Executable file
15
cmd/curl_get_categories.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# TOKEN="your_api_token_here"
|
||||||
|
# ensure to have set TOKEN to a valid value before running
|
||||||
|
# ideally add this to an .envrc file and source it
|
||||||
|
# tokens need to be created with tinker or similar method
|
||||||
|
|
||||||
|
|
||||||
|
URL='http://127.0.0.1:8000/api/categories'
|
||||||
|
|
||||||
|
curl -s -X GET \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
$URL
|
||||||
|
|
||||||
14
cmd/curl_get_categories_anon.sh
Executable file
14
cmd/curl_get_categories_anon.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# TOKEN="your_api_token_here"
|
||||||
|
# ensure to have set TOKEN to a valid value before running
|
||||||
|
# ideally add this to an .envrc file and source it
|
||||||
|
# tokens need to be created with tinker or similar method
|
||||||
|
|
||||||
|
|
||||||
|
URL='http://127.0.0.1:8000/api/categories'
|
||||||
|
|
||||||
|
curl -s -X GET \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
$URL
|
||||||
|
|
||||||
23
database/factories/CategoryFactory.php
Normal file
23
database/factories/CategoryFactory.php
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
|
||||||
|
*/
|
||||||
|
class CategoryFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => fake()->unique()->words(2, true),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
18
docker-compose-dev.yml
Normal file
18
docker-compose-dev.yml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
services:
|
||||||
|
#PHP Service
|
||||||
|
app:
|
||||||
|
image: quay.io/marshyon/share-lt:0.0.1
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
command: sh -c "php artisan optimize:clear && php artisan serve --host=0.0.0.0 --port=8000"
|
||||||
|
volumes:
|
||||||
|
- ./.env:/var/www/.env
|
||||||
|
- ./database/database.sqlite:/var/www/database/database.sqlite
|
||||||
|
- ./storage:/var/www/storage
|
||||||
|
|
||||||
|
restart: unless-stopped
|
||||||
|
tty: true
|
||||||
|
working_dir: /var/www
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,10 +1,17 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\CategoryController;
|
||||||
use App\Http\Controllers\EntryController;
|
use App\Http\Controllers\EntryController;
|
||||||
use App\Http\Controllers\TextWidgetController;
|
use App\Http\Controllers\TextWidgetController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::middleware('auth:sanctum')->group(function () {
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
Route::get('/categories', [CategoryController::class, 'index']);
|
||||||
|
Route::post('/categories', [CategoryController::class, 'store']);
|
||||||
|
Route::get('/categories/{category}', [CategoryController::class, 'show']);
|
||||||
|
Route::put('/categories/{category}', [CategoryController::class, 'update']);
|
||||||
|
Route::delete('/categories/{category}', [CategoryController::class, 'destroy']);
|
||||||
|
|
||||||
Route::get('/entries', [EntryController::class, 'index']);
|
Route::get('/entries', [EntryController::class, 'index']);
|
||||||
Route::post('/entries', [EntryController::class, 'store']);
|
Route::post('/entries', [EntryController::class, 'store']);
|
||||||
Route::get('/entries/{entry}', [EntryController::class, 'show']);
|
Route::get('/entries/{entry}', [EntryController::class, 'show']);
|
||||||
|
|
|
||||||
171
tests/Feature/CategoryApiTest.php
Normal file
171
tests/Feature/CategoryApiTest.php
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Category;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
use function Pest\Laravel\actingAs;
|
||||||
|
use function Pest\Laravel\deleteJson;
|
||||||
|
use function Pest\Laravel\getJson;
|
||||||
|
use function Pest\Laravel\postJson;
|
||||||
|
use function Pest\Laravel\putJson;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
|
test('index returns all categories', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
Category::factory()->count(3)->create();
|
||||||
|
|
||||||
|
actingAs($user)
|
||||||
|
->getJson('/api/categories')
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertJsonCount(3, 'data');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('index requires authentication', function () {
|
||||||
|
getJson('/api/categories')->assertUnauthorized();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('store creates a new category when user is admin', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->postJson('/api/categories', ['name' => 'Technology'])
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertJsonPath('data.name', 'Technology');
|
||||||
|
|
||||||
|
expect(Category::where('name', 'Technology')->exists())->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('store fails when name is missing', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->postJson('/api/categories', [])
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors(['name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('store fails when name is not unique', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
|
||||||
|
Category::factory()->create(['name' => 'Existing']);
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->postJson('/api/categories', ['name' => 'Existing'])
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors(['name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('store fails when user is not admin', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
actingAs($user)
|
||||||
|
->postJson('/api/categories', ['name' => 'Technology'])
|
||||||
|
->assertForbidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('store requires authentication', function () {
|
||||||
|
postJson('/api/categories', ['name' => 'Technology'])->assertUnauthorized();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('show returns a single category', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$category = Category::factory()->create(['name' => 'Science']);
|
||||||
|
|
||||||
|
actingAs($user)
|
||||||
|
->getJson("/api/categories/{$category->id}")
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertJsonPath('data.name', 'Science')
|
||||||
|
->assertJsonPath('data.id', $category->id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('show requires authentication', function () {
|
||||||
|
$category = Category::factory()->create();
|
||||||
|
|
||||||
|
getJson("/api/categories/{$category->id}")->assertUnauthorized();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update modifies an existing category when user is admin', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
$category = Category::factory()->create(['name' => 'Old Name']);
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->putJson("/api/categories/{$category->id}", ['name' => 'New Name'])
|
||||||
|
->assertSuccessful()
|
||||||
|
->assertJsonPath('data.name', 'New Name');
|
||||||
|
|
||||||
|
expect($category->refresh()->name)->toBe('New Name');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update allows partial updates', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
$category = Category::factory()->create(['name' => 'Original']);
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->putJson("/api/categories/{$category->id}", [])
|
||||||
|
->assertSuccessful();
|
||||||
|
|
||||||
|
expect($category->refresh()->name)->toBe('Original');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update fails when name is not unique', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
|
||||||
|
Category::factory()->create(['name' => 'Existing']);
|
||||||
|
$category = Category::factory()->create(['name' => 'Original']);
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->putJson("/api/categories/{$category->id}", ['name' => 'Existing'])
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors(['name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update fails when user is not admin', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$category = Category::factory()->create();
|
||||||
|
|
||||||
|
actingAs($user)
|
||||||
|
->putJson("/api/categories/{$category->id}", ['name' => 'New Name'])
|
||||||
|
->assertForbidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update requires authentication', function () {
|
||||||
|
$category = Category::factory()->create();
|
||||||
|
|
||||||
|
putJson("/api/categories/{$category->id}", ['name' => 'New Name'])->assertUnauthorized();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('destroy deletes a category when user is admin', function () {
|
||||||
|
$adminEmail = config('app.admin_email');
|
||||||
|
$admin = User::factory()->create(['email' => $adminEmail]);
|
||||||
|
$category = Category::factory()->create();
|
||||||
|
|
||||||
|
actingAs($admin)
|
||||||
|
->deleteJson("/api/categories/{$category->id}")
|
||||||
|
->assertNoContent();
|
||||||
|
|
||||||
|
expect(Category::find($category->id))->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('destroy fails when user is not admin', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$category = Category::factory()->create();
|
||||||
|
|
||||||
|
actingAs($user)
|
||||||
|
->deleteJson("/api/categories/{$category->id}")
|
||||||
|
->assertForbidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('destroy requires authentication', function () {
|
||||||
|
$category = Category::factory()->create();
|
||||||
|
|
||||||
|
deleteJson("/api/categories/{$category->id}")->assertUnauthorized();
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue