feat: implement basic API

with authorization and validation
This commit is contained in:
jon brookes 2026-01-07 16:37:50 +00:00
parent b033262bd7
commit 6fbeedd50c
21 changed files with 599 additions and 10 deletions

View file

@ -0,0 +1,92 @@
<?php
namespace App\Http\Controllers;
use App\Models\Entry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class EntryController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return Entry::all();
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$user = Auth::user();
if (!$user || $user->email !== config('app.admin_email')) {
return response()->json(['message' => 'Forbidden'], 403);
}
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
$validated['slug'] = $this->generateUniqueSlug($validated['title']);
return Entry::create($validated);
}
private function generateUniqueSlug(string $title): string
{
do {
$slug = Str::slug($title) . '-' . Str::random(8);
} while (Entry::where('slug', $slug)->exists());
return $slug;
}
/**
* Display the specified resource.
*/
public function show(Entry $entry)
{
$this->authorize('view', $entry);
return $entry;
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Entry $entry)
{
$validated = $request->validate([
'title' => 'sometimes|required|string|max:255',
'content' => 'sometimes|required|string',
]);
$entry->update($validated);
return $entry;
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Entry $entry)
{
$entry->delete();
return response()->noContent();
}
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Auth::check();
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreEntryRequest 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 [
'title' => 'required|string|max:255',
'content' => 'required|string',
];
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateEntryRequest 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 [
'title' => 'sometimes|required|string|max:255',
'content' => 'sometimes|required|string',
];
}
}

View file

@ -5,7 +5,9 @@ namespace App\Models;
use Filament\Forms\Components\RichEditor\FileAttachmentProviders\SpatieMediaLibraryFileAttachmentProvider;
use Filament\Forms\Components\RichEditor\Models\Concerns\InteractsWithRichContent;
use Filament\Forms\Components\RichEditor\Models\Contracts\HasRichContent;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
@ -17,7 +19,7 @@ class Entry extends Model implements HasRichContent, HasMedia
{
use InteractsWithMedia, InteractsWithRichContent;
use InteractsWithMedia, InteractsWithRichContent, HasFactory;
protected $fillable = [
'title',
@ -43,4 +45,14 @@ class Entry extends Model implements HasRichContent, HasMedia
);
}
protected static function boot()
{
parent::boot();
static::creating(function ($entry) {
if (empty($entry->slug)) {
$entry->slug = Str::slug($entry->title);
}
});
}
}

View file

@ -13,11 +13,12 @@ use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Log as FacadesLog;
use Illuminate\Support\Str;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable, TwoFactorAuthenticatable;
use HasFactory, Notifiable, TwoFactorAuthenticatable, HasApiTokens;
/**
* The attributes that are mass assignable.