finished laravel migration
This commit is contained in:
71
app/Http/Controllers/AuthController.php
Normal file
71
app/Http/Controllers/AuthController.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\Fortify\CreateNewUser;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function register(Request $request, CreateNewUser $creator): JsonResponse
|
||||
{
|
||||
$input = [
|
||||
'name' => $request->input('name') ?? $request->input('username'),
|
||||
'email' => $request->input('email'),
|
||||
'password' => $request->input('password') ?? $request->input('plainPassword'),
|
||||
'password_confirmation' => $request->input('password_confirmation') ?? $request->input('plainPassword'),
|
||||
];
|
||||
|
||||
$user = $creator->create($input);
|
||||
|
||||
$user->sendEmailVerificationNotification();
|
||||
|
||||
return response()->json([
|
||||
'user_id' => $user->id,
|
||||
'email' => $user->email,
|
||||
'message' => 'Verification email sent.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function login(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
|
||||
if (!$user || !Hash::check($request->input('password'), $user->password)) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => ['Invalid credentials.'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$user->hasVerifiedEmail()) {
|
||||
return response()->json([
|
||||
'message' => 'Email not verified.',
|
||||
], 403);
|
||||
}
|
||||
|
||||
$token = $user->createToken('api')->plainTextToken;
|
||||
|
||||
return response()->json([
|
||||
'token' => $token,
|
||||
'user_id' => $user->id,
|
||||
'email' => $user->email,
|
||||
'roles' => $user->roles()->pluck('name')->values(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
$request->user()?->currentAccessToken()?->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
}
|
||||
8
app/Http/Controllers/Controller.php
Normal file
8
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
179
app/Http/Controllers/ForumController.php
Normal file
179
app/Http/Controllers/ForumController.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Forum;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ForumController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Forum::query();
|
||||
|
||||
$parentParam = $request->query('parent');
|
||||
if (is_array($parentParam) && array_key_exists('exists', $parentParam)) {
|
||||
$exists = filter_var($parentParam['exists'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
if ($exists === false) {
|
||||
$query->whereNull('parent_id');
|
||||
} elseif ($exists === true) {
|
||||
$query->whereNotNull('parent_id');
|
||||
}
|
||||
} elseif (is_string($parentParam)) {
|
||||
$parentId = $this->parseIriId($parentParam);
|
||||
if ($parentId !== null) {
|
||||
$query->where('parent_id', $parentId);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->filled('type')) {
|
||||
$query->where('type', $request->query('type'));
|
||||
}
|
||||
|
||||
$forums = $query
|
||||
->orderBy('position')
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->map(fn (Forum $forum) => $this->serializeForum($forum));
|
||||
|
||||
return response()->json($forums);
|
||||
}
|
||||
|
||||
public function show(Forum $forum): JsonResponse
|
||||
{
|
||||
return response()->json($this->serializeForum($forum));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'name' => ['required', 'string', 'max:100'],
|
||||
'description' => ['nullable', 'string'],
|
||||
'type' => ['required', Rule::in(['category', 'forum'])],
|
||||
'parent' => ['nullable', 'string'],
|
||||
]);
|
||||
|
||||
$parentId = $this->parseIriId($data['parent'] ?? null);
|
||||
|
||||
if ($parentId) {
|
||||
$parent = Forum::findOrFail($parentId);
|
||||
if ($parent->type !== 'category') {
|
||||
return response()->json(['message' => 'Parent must be a category.'], 422);
|
||||
}
|
||||
}
|
||||
|
||||
$position = Forum::where('parent_id', $parentId)->max('position');
|
||||
|
||||
$forum = Forum::create([
|
||||
'name' => $data['name'],
|
||||
'description' => $data['description'] ?? null,
|
||||
'type' => $data['type'],
|
||||
'parent_id' => $parentId,
|
||||
'position' => ($position ?? 0) + 1,
|
||||
]);
|
||||
|
||||
return response()->json($this->serializeForum($forum), 201);
|
||||
}
|
||||
|
||||
public function update(Request $request, Forum $forum): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'name' => ['sometimes', 'required', 'string', 'max:100'],
|
||||
'description' => ['nullable', 'string'],
|
||||
'type' => ['sometimes', Rule::in(['category', 'forum'])],
|
||||
'parent' => ['nullable', 'string'],
|
||||
]);
|
||||
|
||||
$parentId = $this->parseIriId($data['parent'] ?? null);
|
||||
|
||||
if (array_key_exists('parent', $data)) {
|
||||
if ($parentId) {
|
||||
$parent = Forum::findOrFail($parentId);
|
||||
if ($parent->type !== 'category') {
|
||||
return response()->json(['message' => 'Parent must be a category.'], 422);
|
||||
}
|
||||
}
|
||||
$forum->parent_id = $parentId;
|
||||
}
|
||||
|
||||
if (array_key_exists('name', $data)) {
|
||||
$forum->name = $data['name'];
|
||||
}
|
||||
|
||||
if (array_key_exists('description', $data)) {
|
||||
$forum->description = $data['description'];
|
||||
}
|
||||
|
||||
if (array_key_exists('type', $data)) {
|
||||
$forum->type = $data['type'];
|
||||
}
|
||||
|
||||
$forum->save();
|
||||
|
||||
return response()->json($this->serializeForum($forum));
|
||||
}
|
||||
|
||||
public function destroy(Forum $forum): JsonResponse
|
||||
{
|
||||
$forum->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
|
||||
public function reorder(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'parentId' => ['nullable'],
|
||||
'orderedIds' => ['required', 'array'],
|
||||
'orderedIds.*' => ['integer'],
|
||||
]);
|
||||
|
||||
$parentId = $data['parentId'] ?? null;
|
||||
if ($parentId === '' || $parentId === 'null') {
|
||||
$parentId = null;
|
||||
} elseif ($parentId !== null) {
|
||||
$parentId = (int) $parentId;
|
||||
}
|
||||
|
||||
foreach ($data['orderedIds'] as $index => $forumId) {
|
||||
Forum::where('id', $forumId)
|
||||
->where('parent_id', $parentId)
|
||||
->update(['position' => $index + 1]);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 'ok']);
|
||||
}
|
||||
|
||||
private function parseIriId(?string $value): ?int
|
||||
{
|
||||
if (!$value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (preg_match('#/forums/(\d+)$#', $value, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function serializeForum(Forum $forum): array
|
||||
{
|
||||
return [
|
||||
'id' => $forum->id,
|
||||
'name' => $forum->name,
|
||||
'description' => $forum->description,
|
||||
'type' => $forum->type,
|
||||
'parent' => $forum->parent_id ? "/api/forums/{$forum->parent_id}" : null,
|
||||
'position' => $forum->position,
|
||||
'created_at' => $forum->created_at?->toIso8601String(),
|
||||
'updated_at' => $forum->updated_at?->toIso8601String(),
|
||||
];
|
||||
}
|
||||
}
|
||||
22
app/Http/Controllers/I18nController.php
Normal file
22
app/Http/Controllers/I18nController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class I18nController extends Controller
|
||||
{
|
||||
public function __invoke(string $locale): JsonResponse
|
||||
{
|
||||
$path = resource_path("lang/{$locale}.json");
|
||||
|
||||
if (!File::exists($path)) {
|
||||
return response()->json([], 404);
|
||||
}
|
||||
|
||||
$contents = File::get($path);
|
||||
|
||||
return response()->json(json_decode($contents, true, 512, JSON_THROW_ON_ERROR));
|
||||
}
|
||||
}
|
||||
86
app/Http/Controllers/PostController.php
Normal file
86
app/Http/Controllers/PostController.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Post;
|
||||
use App\Models\Thread;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PostController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Post::query();
|
||||
|
||||
$threadParam = $request->query('thread');
|
||||
if (is_string($threadParam)) {
|
||||
$threadId = $this->parseIriId($threadParam);
|
||||
if ($threadId !== null) {
|
||||
$query->where('thread_id', $threadId);
|
||||
}
|
||||
}
|
||||
|
||||
$posts = $query
|
||||
->oldest('created_at')
|
||||
->get()
|
||||
->map(fn (Post $post) => $this->serializePost($post));
|
||||
|
||||
return response()->json($posts);
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'body' => ['required', 'string'],
|
||||
'thread' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
$threadId = $this->parseIriId($data['thread']);
|
||||
$thread = Thread::findOrFail($threadId);
|
||||
|
||||
$post = Post::create([
|
||||
'thread_id' => $thread->id,
|
||||
'user_id' => $request->user()?->id,
|
||||
'body' => $data['body'],
|
||||
]);
|
||||
|
||||
return response()->json($this->serializePost($post), 201);
|
||||
}
|
||||
|
||||
public function destroy(Post $post): JsonResponse
|
||||
{
|
||||
$post->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
|
||||
private function parseIriId(?string $value): ?int
|
||||
{
|
||||
if (!$value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (preg_match('#/threads/(\d+)$#', $value, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function serializePost(Post $post): array
|
||||
{
|
||||
return [
|
||||
'id' => $post->id,
|
||||
'body' => $post->body,
|
||||
'thread' => "/api/threads/{$post->thread_id}",
|
||||
'user_id' => $post->user_id,
|
||||
'created_at' => $post->created_at?->toIso8601String(),
|
||||
'updated_at' => $post->updated_at?->toIso8601String(),
|
||||
];
|
||||
}
|
||||
}
|
||||
27
app/Http/Controllers/SettingController.php
Normal file
27
app/Http/Controllers/SettingController.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Setting::query();
|
||||
|
||||
if ($request->filled('key')) {
|
||||
$query->where('key', $request->query('key'));
|
||||
}
|
||||
|
||||
$settings = $query->get()->map(fn (Setting $setting) => [
|
||||
'id' => $setting->id,
|
||||
'key' => $setting->key,
|
||||
'value' => $setting->value,
|
||||
]);
|
||||
|
||||
return response()->json($settings);
|
||||
}
|
||||
}
|
||||
98
app/Http/Controllers/ThreadController.php
Normal file
98
app/Http/Controllers/ThreadController.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Forum;
|
||||
use App\Models\Thread;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ThreadController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Thread::query();
|
||||
|
||||
$forumParam = $request->query('forum');
|
||||
if (is_string($forumParam)) {
|
||||
$forumId = $this->parseIriId($forumParam);
|
||||
if ($forumId !== null) {
|
||||
$query->where('forum_id', $forumId);
|
||||
}
|
||||
}
|
||||
|
||||
$threads = $query
|
||||
->latest('created_at')
|
||||
->get()
|
||||
->map(fn (Thread $thread) => $this->serializeThread($thread));
|
||||
|
||||
return response()->json($threads);
|
||||
}
|
||||
|
||||
public function show(Thread $thread): JsonResponse
|
||||
{
|
||||
return response()->json($this->serializeThread($thread));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'title' => ['required', 'string'],
|
||||
'body' => ['required', 'string'],
|
||||
'forum' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
$forumId = $this->parseIriId($data['forum']);
|
||||
$forum = Forum::findOrFail($forumId);
|
||||
|
||||
if ($forum->type !== 'forum') {
|
||||
return response()->json(['message' => 'Threads can only be created inside forums.'], 422);
|
||||
}
|
||||
|
||||
$thread = Thread::create([
|
||||
'forum_id' => $forum->id,
|
||||
'user_id' => $request->user()?->id,
|
||||
'title' => $data['title'],
|
||||
'body' => $data['body'],
|
||||
]);
|
||||
|
||||
return response()->json($this->serializeThread($thread), 201);
|
||||
}
|
||||
|
||||
public function destroy(Thread $thread): JsonResponse
|
||||
{
|
||||
$thread->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
|
||||
private function parseIriId(?string $value): ?int
|
||||
{
|
||||
if (!$value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (preg_match('#/forums/(\d+)$#', $value, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function serializeThread(Thread $thread): array
|
||||
{
|
||||
return [
|
||||
'id' => $thread->id,
|
||||
'title' => $thread->title,
|
||||
'body' => $thread->body,
|
||||
'forum' => "/api/forums/{$thread->forum_id}",
|
||||
'user_id' => $thread->user_id,
|
||||
'created_at' => $thread->created_at?->toIso8601String(),
|
||||
'updated_at' => $thread->updated_at?->toIso8601String(),
|
||||
];
|
||||
}
|
||||
}
|
||||
25
app/Http/Controllers/UserController.php
Normal file
25
app/Http/Controllers/UserController.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$users = User::query()
|
||||
->with('roles')
|
||||
->orderBy('id')
|
||||
->get()
|
||||
->map(fn (User $user) => [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
'roles' => $user->roles->pluck('name')->values(),
|
||||
]);
|
||||
|
||||
return response()->json($users);
|
||||
}
|
||||
}
|
||||
20
app/Http/Controllers/VersionController.php
Normal file
20
app/Http/Controllers/VersionController.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class VersionController extends Controller
|
||||
{
|
||||
public function __invoke(): JsonResponse
|
||||
{
|
||||
$version = Setting::where('key', 'version')->value('value');
|
||||
$build = Setting::where('key', 'build')->value('value');
|
||||
|
||||
return response()->json([
|
||||
'version' => $version,
|
||||
'build' => $build !== null ? (int) $build : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user