update deploy
This commit is contained in:
140
app/Http/Controllers/Api/Admin/AnnouncementController.php
Normal file
140
app/Http/Controllers/Api/Admin/AnnouncementController.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Announcement\CreateAnnouncementAction;
|
||||
use App\Actions\Announcement\DeleteAnnouncementAction;
|
||||
use App\Actions\Announcement\UpdateAnnouncementAction;
|
||||
use App\DTOs\AnnouncementData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Announcement\StoreAnnouncementRequest;
|
||||
use App\Http\Requests\Announcement\UpdateAnnouncementRequest;
|
||||
use App\Http\Resources\AnnouncementResource;
|
||||
use App\Models\Announcement;
|
||||
use App\Repositories\Contracts\AnnouncementRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class AnnouncementController extends Controller
|
||||
{
|
||||
public function __construct(private AnnouncementRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/announcements',
|
||||
summary: 'Duyuruları listele (Admin)',
|
||||
tags: ['Admin - Announcements'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'category', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'featured', in: 'query', required: false, schema: new OA\Schema(type: 'boolean')),
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'sort', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Duyuru listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$announcements = $this->repository->paginate(
|
||||
$request->only(['category', 'featured', 'search', 'sort']),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return AnnouncementResource::collection($announcements);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/announcements',
|
||||
summary: 'Yeni duyuru oluştur',
|
||||
tags: ['Admin - Announcements'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['title', 'slug', 'category', 'content'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'slug', type: 'string'),
|
||||
new OA\Property(property: 'category', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'string'),
|
||||
new OA\Property(property: 'excerpt', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string'),
|
||||
new OA\Property(property: 'is_featured', type: 'boolean'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'published_at', type: 'string', format: 'date-time'),
|
||||
new OA\Property(property: 'meta_title', type: 'string'),
|
||||
new OA\Property(property: 'meta_description', type: 'string'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Duyuru oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreAnnouncementRequest $request, CreateAnnouncementAction $action): JsonResponse
|
||||
{
|
||||
$dto = AnnouncementData::fromArray($request->validated());
|
||||
$announcement = $action->execute($dto);
|
||||
|
||||
return response()->json(new AnnouncementResource($announcement), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/announcements/{announcement}',
|
||||
summary: 'Duyuru detayı (Admin)',
|
||||
tags: ['Admin - Announcements'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'announcement', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Duyuru detayı')],
|
||||
)]
|
||||
public function show(Announcement $announcement): JsonResponse
|
||||
{
|
||||
return response()->json(new AnnouncementResource($announcement));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/announcements/{announcement}',
|
||||
summary: 'Duyuru güncelle',
|
||||
tags: ['Admin - Announcements'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'announcement', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'slug', type: 'string'),
|
||||
new OA\Property(property: 'category', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'string'),
|
||||
new OA\Property(property: 'excerpt', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string'),
|
||||
new OA\Property(property: 'is_featured', type: 'boolean'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Duyuru güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateAnnouncementRequest $request, Announcement $announcement, UpdateAnnouncementAction $action): JsonResponse
|
||||
{
|
||||
$dto = AnnouncementData::fromArray(array_merge($announcement->toArray(), $request->validated()));
|
||||
$announcement = $action->execute($announcement, $dto);
|
||||
|
||||
return response()->json(new AnnouncementResource($announcement));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/announcements/{announcement}',
|
||||
summary: 'Duyuru sil',
|
||||
tags: ['Admin - Announcements'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'announcement', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Duyuru silindi')],
|
||||
)]
|
||||
public function destroy(Announcement $announcement, DeleteAnnouncementAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($announcement);
|
||||
|
||||
return response()->json(['message' => 'Duyuru silindi.']);
|
||||
}
|
||||
}
|
||||
118
app/Http/Controllers/Api/Admin/AuthController.php
Normal file
118
app/Http/Controllers/Api/Admin/AuthController.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Auth\LoginRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
#[OA\Post(
|
||||
path: '/api/admin/login',
|
||||
summary: 'Admin girişi',
|
||||
description: 'E-posta ve şifre ile giriş yaparak Sanctum token alır.',
|
||||
tags: ['Auth'],
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['email', 'password'],
|
||||
properties: [
|
||||
new OA\Property(property: 'email', type: 'string', format: 'email', example: 'admin@bogazicidenizcilik.com.tr'),
|
||||
new OA\Property(property: 'password', type: 'string', format: 'password', example: 'password'),
|
||||
],
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Başarılı giriş', content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'data', type: 'object', properties: [
|
||||
new OA\Property(property: 'token', type: 'string'),
|
||||
new OA\Property(property: 'user', type: 'object'),
|
||||
]),
|
||||
],
|
||||
)),
|
||||
new OA\Response(response: 401, description: 'Geçersiz kimlik bilgileri'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function login(LoginRequest $request): JsonResponse
|
||||
{
|
||||
if (! Auth::attempt($request->only('email', 'password'))) {
|
||||
return response()->json([
|
||||
'message' => 'Geçersiz e-posta veya şifre.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
/** @var User $user */
|
||||
$user = Auth::user();
|
||||
|
||||
$token = $user->createToken('admin-token')->plainTextToken;
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'token' => $token,
|
||||
'user' => [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
'roles' => $user->getRoleNames(),
|
||||
'permissions' => $user->getAllPermissions()->pluck('name'),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/me',
|
||||
summary: 'Mevcut kullanıcı bilgileri',
|
||||
description: 'Oturum açmış kullanıcının bilgilerini, rollerini ve izinlerini döndürür.',
|
||||
security: [['sanctum' => []]],
|
||||
tags: ['Auth'],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kullanıcı bilgileri'),
|
||||
new OA\Response(response: 401, description: 'Yetkisiz erişim'),
|
||||
],
|
||||
)]
|
||||
public function me(Request $request): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->user();
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
'roles' => $user->getRoleNames(),
|
||||
'permissions' => $user->getAllPermissions()->pluck('name'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/logout',
|
||||
summary: 'Çıkış yap',
|
||||
description: 'Mevcut token\'ı iptal eder.',
|
||||
security: [['sanctum' => []]],
|
||||
tags: ['Auth'],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Başarıyla çıkış yapıldı'),
|
||||
new OA\Response(response: 401, description: 'Yetkisiz erişim'),
|
||||
],
|
||||
)]
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->user();
|
||||
$user->currentAccessToken()->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Başarıyla çıkış yapıldı.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
172
app/Http/Controllers/Api/Admin/BlockController.php
Normal file
172
app/Http/Controllers/Api/Admin/BlockController.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\PageBlockResource;
|
||||
use App\Models\Page;
|
||||
use App\Models\PageBlock;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class BlockController extends Controller
|
||||
{
|
||||
#[OA\Get(
|
||||
path: '/api/admin/pages/{page}/blocks',
|
||||
summary: 'Sayfa bloklarını listele',
|
||||
tags: ['Admin - Page Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Blok listesi')],
|
||||
)]
|
||||
public function index(Page $page): AnonymousResourceCollection
|
||||
{
|
||||
return PageBlockResource::collection(
|
||||
$page->blocks()->orderBy('order_index')->get()
|
||||
);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/pages/{page}/blocks',
|
||||
summary: 'Yeni blok oluştur',
|
||||
tags: ['Admin - Page Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['type', 'content'],
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Blok oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(Request $request, Page $page): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'type' => ['required', 'string', 'max:50'],
|
||||
'content' => ['present', 'array'],
|
||||
'order_index' => ['sometimes', 'integer', 'min:0'],
|
||||
'is_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$validated['order_index'] ??= $page->blocks()->max('order_index') + 1;
|
||||
|
||||
$block = $page->blocks()->create($validated);
|
||||
|
||||
return response()->json(new PageBlockResource($block), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/pages/{page}/blocks/{block}',
|
||||
summary: 'Blok detayı',
|
||||
tags: ['Admin - Page Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'block', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Blok detayı')],
|
||||
)]
|
||||
public function show(Page $page, PageBlock $block): JsonResponse
|
||||
{
|
||||
return response()->json(new PageBlockResource($block));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/pages/{page}/blocks/{block}',
|
||||
summary: 'Blok güncelle',
|
||||
tags: ['Admin - Page Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'block', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Blok güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(Request $request, Page $page, PageBlock $block): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'type' => ['sometimes', 'string', 'max:50'],
|
||||
'content' => ['sometimes', 'array'],
|
||||
'order_index' => ['sometimes', 'integer', 'min:0'],
|
||||
'is_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$block->update($validated);
|
||||
|
||||
return response()->json(new PageBlockResource($block->fresh()));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/pages/{page}/blocks/{block}',
|
||||
summary: 'Blok sil',
|
||||
tags: ['Admin - Page Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'block', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Blok silindi')],
|
||||
)]
|
||||
public function destroy(Page $page, PageBlock $block): JsonResponse
|
||||
{
|
||||
$block->delete();
|
||||
|
||||
return response()->json(['message' => 'Blok silindi.']);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/pages/{page}/blocks/reorder',
|
||||
summary: 'Blok sıralamasını güncelle',
|
||||
tags: ['Admin - Page Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['items'],
|
||||
properties: [
|
||||
new OA\Property(property: 'items', type: 'array', items: new OA\Items(
|
||||
properties: [
|
||||
new OA\Property(property: 'id', type: 'integer'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
responses: [new OA\Response(response: 200, description: 'Sıralama güncellendi')],
|
||||
)]
|
||||
public function reorder(Request $request, Page $page): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'items' => ['required', 'array', 'min:1'],
|
||||
'items.*.id' => ['required', 'integer', 'exists:page_blocks,id'],
|
||||
'items.*.order_index' => ['required', 'integer', 'min:0'],
|
||||
]);
|
||||
|
||||
foreach ($validated['items'] as $item) {
|
||||
$page->blocks()
|
||||
->where('id', $item['id'])
|
||||
->update(['order_index' => $item['order_index']]);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Blok sıralaması güncellendi.']);
|
||||
}
|
||||
}
|
||||
147
app/Http/Controllers/Api/Admin/CategoryController.php
Normal file
147
app/Http/Controllers/Api/Admin/CategoryController.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Category\CreateCategoryAction;
|
||||
use App\Actions\Category\DeleteCategoryAction;
|
||||
use App\Actions\Category\UpdateCategoryAction;
|
||||
use App\DTOs\CategoryData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Category\StoreCategoryRequest;
|
||||
use App\Http\Requests\Category\UpdateCategoryRequest;
|
||||
use App\Http\Resources\CategoryResource;
|
||||
use App\Models\Category;
|
||||
use App\Repositories\Contracts\CategoryRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
public function __construct(private CategoryRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/categories',
|
||||
summary: 'Kategorileri listele (Admin)',
|
||||
tags: ['Admin - Categories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Kategori listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$categories = $this->repository->paginate(
|
||||
filters: $request->only('search'),
|
||||
perPage: $request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return CategoryResource::collection($categories);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/categories',
|
||||
summary: 'Yeni kategori oluştur',
|
||||
tags: ['Admin - Categories'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['name'],
|
||||
properties: [
|
||||
new OA\Property(property: 'name', type: 'string'),
|
||||
new OA\Property(property: 'slug', type: 'string'),
|
||||
new OA\Property(property: 'description', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string'),
|
||||
new OA\Property(property: 'icon', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
new OA\Property(property: 'meta_title', type: 'string'),
|
||||
new OA\Property(property: 'meta_description', type: 'string'),
|
||||
],
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Kategori oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreCategoryRequest $request, CreateCategoryAction $action): JsonResponse
|
||||
{
|
||||
$dto = CategoryData::fromArray($request->validated());
|
||||
$category = $action->execute($dto);
|
||||
|
||||
return (new CategoryResource($category))
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/categories/{category}',
|
||||
summary: 'Kategori detayı (Admin)',
|
||||
tags: ['Admin - Categories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'category', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kategori detayı'),
|
||||
new OA\Response(response: 404, description: 'Bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function show(Category $category): CategoryResource
|
||||
{
|
||||
return new CategoryResource($category);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/categories/{category}',
|
||||
summary: 'Kategori güncelle',
|
||||
tags: ['Admin - Categories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'category', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'name', type: 'string'),
|
||||
new OA\Property(property: 'slug', type: 'string'),
|
||||
new OA\Property(property: 'description', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string'),
|
||||
new OA\Property(property: 'icon', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
new OA\Property(property: 'meta_title', type: 'string'),
|
||||
new OA\Property(property: 'meta_description', type: 'string'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kategori güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateCategoryRequest $request, Category $category, UpdateCategoryAction $action): CategoryResource
|
||||
{
|
||||
$dto = CategoryData::fromArray($request->validated());
|
||||
$category = $action->execute($category, $dto);
|
||||
|
||||
return new CategoryResource($category);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/categories/{category}',
|
||||
summary: 'Kategori sil',
|
||||
tags: ['Admin - Categories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'category', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kategori silindi'),
|
||||
new OA\Response(response: 404, description: 'Bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function destroy(Category $category, DeleteCategoryAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($category);
|
||||
|
||||
return response()->json(['message' => 'Kategori başarıyla silindi.']);
|
||||
}
|
||||
}
|
||||
94
app/Http/Controllers/Api/Admin/CommentController.php
Normal file
94
app/Http/Controllers/Api/Admin/CommentController.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Comment\DeleteCommentAction;
|
||||
use App\Actions\Comment\UpdateCommentAction;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Comment\UpdateCommentRequest;
|
||||
use App\Http\Resources\CommentResource;
|
||||
use App\Models\Comment;
|
||||
use App\Repositories\Contracts\CommentRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
public function __construct(private CommentRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/comments',
|
||||
summary: 'Yorumları listele (Admin)',
|
||||
tags: ['Admin - Comments'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'is_approved', in: 'query', required: false, schema: new OA\Schema(type: 'boolean')),
|
||||
new OA\Parameter(name: 'commentable_type', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Yorum listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$comments = $this->repository->paginate(
|
||||
$request->only(['is_approved', 'commentable_type', 'search']),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return CommentResource::collection($comments);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/comments/{comment}',
|
||||
summary: 'Yorum detayı',
|
||||
tags: ['Admin - Comments'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'comment', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Yorum detayı')],
|
||||
)]
|
||||
public function show(Comment $comment): JsonResponse
|
||||
{
|
||||
return response()->json(new CommentResource($comment));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/comments/{comment}',
|
||||
summary: 'Yorum güncelle (onayla/reddet)',
|
||||
tags: ['Admin - Comments'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'comment', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'is_approved', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Yorum güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateCommentRequest $request, Comment $comment, UpdateCommentAction $action): JsonResponse
|
||||
{
|
||||
$comment = $action->execute($comment, $request->validated());
|
||||
|
||||
return response()->json(new CommentResource($comment));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/comments/{comment}',
|
||||
summary: 'Yorum sil',
|
||||
tags: ['Admin - Comments'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'comment', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Yorum silindi')],
|
||||
)]
|
||||
public function destroy(Comment $comment, DeleteCommentAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($comment);
|
||||
|
||||
return response()->json(['message' => 'Yorum silindi.']);
|
||||
}
|
||||
}
|
||||
172
app/Http/Controllers/Api/Admin/CourseBlockController.php
Normal file
172
app/Http/Controllers/Api/Admin/CourseBlockController.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\CourseBlockResource;
|
||||
use App\Models\Course;
|
||||
use App\Models\CourseBlock;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class CourseBlockController extends Controller
|
||||
{
|
||||
#[OA\Get(
|
||||
path: '/api/admin/courses/{course}/blocks',
|
||||
summary: 'Eğitim bloklarını listele',
|
||||
tags: ['Admin - Course Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Blok listesi')],
|
||||
)]
|
||||
public function index(Course $course): AnonymousResourceCollection
|
||||
{
|
||||
return CourseBlockResource::collection(
|
||||
$course->blocks()->orderBy('order_index')->get()
|
||||
);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/courses/{course}/blocks',
|
||||
summary: 'Yeni eğitim bloğu oluştur',
|
||||
tags: ['Admin - Course Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['type', 'content'],
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Blok oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(Request $request, Course $course): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'type' => ['required', 'string', 'max:50'],
|
||||
'content' => ['present', 'array'],
|
||||
'order_index' => ['sometimes', 'integer', 'min:0'],
|
||||
'is_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$validated['order_index'] ??= $course->blocks()->max('order_index') + 1;
|
||||
|
||||
$block = $course->blocks()->create($validated);
|
||||
|
||||
return response()->json(new CourseBlockResource($block), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/courses/{course}/blocks/{block}',
|
||||
summary: 'Eğitim blok detayı',
|
||||
tags: ['Admin - Course Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'block', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Blok detayı')],
|
||||
)]
|
||||
public function show(Course $course, CourseBlock $block): JsonResponse
|
||||
{
|
||||
return response()->json(new CourseBlockResource($block));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/courses/{course}/blocks/{block}',
|
||||
summary: 'Eğitim bloğu güncelle',
|
||||
tags: ['Admin - Course Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'block', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Blok güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(Request $request, Course $course, CourseBlock $block): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'type' => ['sometimes', 'string', 'max:50'],
|
||||
'content' => ['sometimes', 'array'],
|
||||
'order_index' => ['sometimes', 'integer', 'min:0'],
|
||||
'is_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$block->update($validated);
|
||||
|
||||
return response()->json(new CourseBlockResource($block->fresh()));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/courses/{course}/blocks/{block}',
|
||||
summary: 'Eğitim bloğu sil',
|
||||
tags: ['Admin - Course Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'block', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Blok silindi')],
|
||||
)]
|
||||
public function destroy(Course $course, CourseBlock $block): JsonResponse
|
||||
{
|
||||
$block->delete();
|
||||
|
||||
return response()->json(['message' => 'Blok silindi.']);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/courses/{course}/blocks/reorder',
|
||||
summary: 'Eğitim blok sıralamasını güncelle',
|
||||
tags: ['Admin - Course Blocks'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['items'],
|
||||
properties: [
|
||||
new OA\Property(property: 'items', type: 'array', items: new OA\Items(
|
||||
properties: [
|
||||
new OA\Property(property: 'id', type: 'integer'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
responses: [new OA\Response(response: 200, description: 'Sıralama güncellendi')],
|
||||
)]
|
||||
public function reorder(Request $request, Course $course): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'items' => ['required', 'array', 'min:1'],
|
||||
'items.*.id' => ['required', 'integer', 'exists:course_blocks,id'],
|
||||
'items.*.order_index' => ['required', 'integer', 'min:0'],
|
||||
]);
|
||||
|
||||
foreach ($validated['items'] as $item) {
|
||||
$course->blocks()
|
||||
->where('id', $item['id'])
|
||||
->update(['order_index' => $item['order_index']]);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Blok sıralaması güncellendi.']);
|
||||
}
|
||||
}
|
||||
163
app/Http/Controllers/Api/Admin/CourseController.php
Normal file
163
app/Http/Controllers/Api/Admin/CourseController.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Course\CreateCourseAction;
|
||||
use App\Actions\Course\DeleteCourseAction;
|
||||
use App\Actions\Course\UpdateCourseAction;
|
||||
use App\DTOs\CourseData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Course\StoreCourseRequest;
|
||||
use App\Http\Requests\Course\UpdateCourseRequest;
|
||||
use App\Http\Resources\CourseResource;
|
||||
use App\Models\Course;
|
||||
use App\Repositories\Contracts\CourseRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class CourseController extends Controller
|
||||
{
|
||||
public function __construct(private CourseRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/courses',
|
||||
summary: 'Eğitimleri listele (Admin)',
|
||||
tags: ['Admin - Courses'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'category', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'sort', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Eğitim listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$courses = $this->repository->paginate(
|
||||
filters: $request->only('category', 'search', 'sort'),
|
||||
perPage: $request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return CourseResource::collection($courses);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/courses',
|
||||
summary: 'Yeni eğitim oluştur',
|
||||
tags: ['Admin - Courses'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['category_id', 'title', 'slug', 'desc', 'long_desc', 'duration'],
|
||||
properties: [
|
||||
new OA\Property(property: 'category_id', type: 'integer', description: 'Kategori ID'),
|
||||
new OA\Property(property: 'slug', type: 'string', description: 'URL slug (unique)'),
|
||||
new OA\Property(property: 'title', type: 'string', description: 'Eğitim başlığı'),
|
||||
new OA\Property(property: 'sub', type: 'string', nullable: true, description: 'Alt başlık. Örn: STCW II/1'),
|
||||
new OA\Property(property: 'desc', type: 'string', description: 'Kısa açıklama'),
|
||||
new OA\Property(property: 'long_desc', type: 'string', description: 'Detaylı açıklama'),
|
||||
new OA\Property(property: 'duration', type: 'string', description: 'Süre. Örn: 5 Gün'),
|
||||
new OA\Property(property: 'students', type: 'integer', description: 'Öğrenci sayısı'),
|
||||
new OA\Property(property: 'rating', type: 'number', format: 'float', description: 'Puan (0-5)'),
|
||||
new OA\Property(property: 'badge', type: 'string', nullable: true, description: 'Rozet. Örn: Simülatör'),
|
||||
new OA\Property(property: 'image', type: 'string', nullable: true, description: 'Görsel path'),
|
||||
new OA\Property(property: 'price', type: 'string', nullable: true, description: 'Fiyat. Örn: 5.000 TL'),
|
||||
new OA\Property(property: 'includes', type: 'array', items: new OA\Items(type: 'string'), nullable: true, description: 'Fiyata dahil olanlar'),
|
||||
new OA\Property(property: 'requirements', type: 'array', items: new OA\Items(type: 'string'), nullable: true, description: 'Katılım koşulları'),
|
||||
new OA\Property(property: 'meta_title', type: 'string', nullable: true, description: 'SEO Title'),
|
||||
new OA\Property(property: 'meta_description', type: 'string', nullable: true, description: 'SEO Description'),
|
||||
new OA\Property(property: 'scope', type: 'array', items: new OA\Items(type: 'string'), nullable: true, description: 'Eğitim kapsamı konu başlıkları'),
|
||||
new OA\Property(property: 'standard', type: 'string', nullable: true, description: 'Uyum standardı. Örn: STCW / IMO Uyumlu'),
|
||||
new OA\Property(property: 'language', type: 'string', nullable: true, description: 'Eğitim dili. Varsayılan: Türkçe'),
|
||||
new OA\Property(property: 'location', type: 'string', nullable: true, description: 'Varsayılan lokasyon. Örn: Kadıköy, İstanbul'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Eğitim oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreCourseRequest $request, CreateCourseAction $action): JsonResponse
|
||||
{
|
||||
$dto = CourseData::fromArray($request->validated());
|
||||
$course = $action->execute($dto);
|
||||
|
||||
return (new CourseResource($course->load('category')))
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/courses/{course}',
|
||||
summary: 'Eğitim detayı (Admin)',
|
||||
tags: ['Admin - Courses'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Eğitim detayı')],
|
||||
)]
|
||||
public function show(Course $course): CourseResource
|
||||
{
|
||||
return new CourseResource($course->load(['category', 'schedules', 'blocks']));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/courses/{course}',
|
||||
summary: 'Eğitim güncelle',
|
||||
tags: ['Admin - Courses'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['category_id', 'title', 'slug', 'desc', 'long_desc', 'duration'],
|
||||
properties: [
|
||||
new OA\Property(property: 'category_id', type: 'integer', description: 'Kategori ID'),
|
||||
new OA\Property(property: 'slug', type: 'string', description: 'URL slug (unique)'),
|
||||
new OA\Property(property: 'title', type: 'string', description: 'Eğitim başlığı'),
|
||||
new OA\Property(property: 'sub', type: 'string', nullable: true, description: 'Alt başlık'),
|
||||
new OA\Property(property: 'desc', type: 'string', description: 'Kısa açıklama'),
|
||||
new OA\Property(property: 'long_desc', type: 'string', description: 'Detaylı açıklama'),
|
||||
new OA\Property(property: 'duration', type: 'string', description: 'Süre. Örn: 5 Gün'),
|
||||
new OA\Property(property: 'students', type: 'integer', description: 'Öğrenci sayısı'),
|
||||
new OA\Property(property: 'rating', type: 'number', format: 'float', description: 'Puan (0-5)'),
|
||||
new OA\Property(property: 'badge', type: 'string', nullable: true, description: 'Rozet'),
|
||||
new OA\Property(property: 'image', type: 'string', nullable: true, description: 'Görsel path'),
|
||||
new OA\Property(property: 'price', type: 'string', nullable: true, description: 'Fiyat'),
|
||||
new OA\Property(property: 'includes', type: 'array', items: new OA\Items(type: 'string'), nullable: true, description: 'Fiyata dahil olanlar'),
|
||||
new OA\Property(property: 'requirements', type: 'array', items: new OA\Items(type: 'string'), nullable: true, description: 'Katılım koşulları'),
|
||||
new OA\Property(property: 'meta_title', type: 'string', nullable: true, description: 'SEO Title'),
|
||||
new OA\Property(property: 'meta_description', type: 'string', nullable: true, description: 'SEO Description'),
|
||||
new OA\Property(property: 'scope', type: 'array', items: new OA\Items(type: 'string'), nullable: true, description: 'Eğitim kapsamı konu başlıkları'),
|
||||
new OA\Property(property: 'standard', type: 'string', nullable: true, description: 'Uyum standardı'),
|
||||
new OA\Property(property: 'language', type: 'string', nullable: true, description: 'Eğitim dili'),
|
||||
new OA\Property(property: 'location', type: 'string', nullable: true, description: 'Varsayılan lokasyon'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Eğitim güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateCourseRequest $request, Course $course, UpdateCourseAction $action): CourseResource
|
||||
{
|
||||
$dto = CourseData::fromArray($request->validated());
|
||||
$course = $action->execute($course, $dto);
|
||||
|
||||
return new CourseResource($course->load('category'));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/courses/{course}',
|
||||
summary: 'Eğitim sil',
|
||||
tags: ['Admin - Courses'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'course', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Eğitim silindi')],
|
||||
)]
|
||||
public function destroy(Course $course, DeleteCourseAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($course);
|
||||
|
||||
return response()->json(['message' => 'Eğitim başarıyla silindi.']);
|
||||
}
|
||||
}
|
||||
128
app/Http/Controllers/Api/Admin/FaqController.php
Normal file
128
app/Http/Controllers/Api/Admin/FaqController.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Faq\CreateFaqAction;
|
||||
use App\Actions\Faq\DeleteFaqAction;
|
||||
use App\Actions\Faq\UpdateFaqAction;
|
||||
use App\DTOs\FaqData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Faq\StoreFaqRequest;
|
||||
use App\Http\Requests\Faq\UpdateFaqRequest;
|
||||
use App\Http\Resources\FaqResource;
|
||||
use App\Models\Faq;
|
||||
use App\Repositories\Contracts\FaqRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class FaqController extends Controller
|
||||
{
|
||||
public function __construct(private FaqRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/faqs',
|
||||
summary: 'SSS listele (Admin)',
|
||||
tags: ['Admin - FAQs'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'category', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 50)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'SSS listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$faqs = $this->repository->paginate(
|
||||
$request->only(['category']),
|
||||
$request->integer('per_page', 50),
|
||||
);
|
||||
|
||||
return FaqResource::collection($faqs);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/faqs',
|
||||
summary: 'Yeni SSS oluştur',
|
||||
tags: ['Admin - FAQs'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['question', 'answer', 'category'],
|
||||
properties: [
|
||||
new OA\Property(property: 'question', type: 'string'),
|
||||
new OA\Property(property: 'answer', type: 'string'),
|
||||
new OA\Property(property: 'category', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'SSS oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreFaqRequest $request, CreateFaqAction $action): JsonResponse
|
||||
{
|
||||
$dto = FaqData::fromArray($request->validated());
|
||||
$faq = $action->execute($dto);
|
||||
|
||||
return response()->json(new FaqResource($faq), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/faqs/{faq}',
|
||||
summary: 'SSS detayı',
|
||||
tags: ['Admin - FAQs'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'faq', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'SSS detayı')],
|
||||
)]
|
||||
public function show(Faq $faq): JsonResponse
|
||||
{
|
||||
return response()->json(new FaqResource($faq));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/faqs/{faq}',
|
||||
summary: 'SSS güncelle',
|
||||
tags: ['Admin - FAQs'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'faq', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'question', type: 'string'),
|
||||
new OA\Property(property: 'answer', type: 'string'),
|
||||
new OA\Property(property: 'category', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'SSS güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateFaqRequest $request, Faq $faq, UpdateFaqAction $action): JsonResponse
|
||||
{
|
||||
$dto = FaqData::fromArray(array_merge($faq->toArray(), $request->validated()));
|
||||
$faq = $action->execute($faq, $dto);
|
||||
|
||||
return response()->json(new FaqResource($faq));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/faqs/{faq}',
|
||||
summary: 'SSS sil',
|
||||
tags: ['Admin - FAQs'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'faq', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'SSS silindi')],
|
||||
)]
|
||||
public function destroy(Faq $faq, DeleteFaqAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($faq);
|
||||
|
||||
return response()->json(['message' => 'SSS silindi.']);
|
||||
}
|
||||
}
|
||||
127
app/Http/Controllers/Api/Admin/GuideCardController.php
Normal file
127
app/Http/Controllers/Api/Admin/GuideCardController.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\GuideCard\CreateGuideCardAction;
|
||||
use App\Actions\GuideCard\DeleteGuideCardAction;
|
||||
use App\Actions\GuideCard\UpdateGuideCardAction;
|
||||
use App\DTOs\GuideCardData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\GuideCard\StoreGuideCardRequest;
|
||||
use App\Http\Requests\GuideCard\UpdateGuideCardRequest;
|
||||
use App\Http\Resources\GuideCardResource;
|
||||
use App\Models\GuideCard;
|
||||
use App\Repositories\Contracts\GuideCardRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class GuideCardController extends Controller
|
||||
{
|
||||
public function __construct(private GuideCardRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/guide-cards',
|
||||
summary: 'Rehber kartları listele (Admin)',
|
||||
tags: ['Admin - Guide Cards'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15))],
|
||||
responses: [new OA\Response(response: 200, description: 'Kart listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$cards = $this->repository->paginate(
|
||||
$request->only([]),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return GuideCardResource::collection($cards);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/guide-cards',
|
||||
summary: 'Yeni rehber kartı oluştur',
|
||||
tags: ['Admin - Guide Cards'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['title', 'description', 'icon'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'description', type: 'string'),
|
||||
new OA\Property(property: 'icon', type: 'string'),
|
||||
new OA\Property(property: 'url', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Kart oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreGuideCardRequest $request, CreateGuideCardAction $action): JsonResponse
|
||||
{
|
||||
$dto = GuideCardData::fromArray($request->validated());
|
||||
$card = $action->execute($dto);
|
||||
|
||||
return response()->json(new GuideCardResource($card), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/guide-cards/{guideCard}',
|
||||
summary: 'Rehber kart detayı',
|
||||
tags: ['Admin - Guide Cards'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'guideCard', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Kart detayı')],
|
||||
)]
|
||||
public function show(GuideCard $guideCard): JsonResponse
|
||||
{
|
||||
return response()->json(new GuideCardResource($guideCard));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/guide-cards/{guideCard}',
|
||||
summary: 'Rehber kart güncelle',
|
||||
tags: ['Admin - Guide Cards'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'guideCard', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'description', type: 'string'),
|
||||
new OA\Property(property: 'icon', type: 'string'),
|
||||
new OA\Property(property: 'url', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kart güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateGuideCardRequest $request, GuideCard $guideCard, UpdateGuideCardAction $action): JsonResponse
|
||||
{
|
||||
$dto = GuideCardData::fromArray(array_merge($guideCard->toArray(), $request->validated()));
|
||||
$guideCard = $action->execute($guideCard, $dto);
|
||||
|
||||
return response()->json(new GuideCardResource($guideCard));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/guide-cards/{guideCard}',
|
||||
summary: 'Rehber kart sil',
|
||||
tags: ['Admin - Guide Cards'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'guideCard', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Kart silindi')],
|
||||
)]
|
||||
public function destroy(GuideCard $guideCard, DeleteGuideCardAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($guideCard);
|
||||
|
||||
return response()->json(['message' => 'Rehber kartı silindi.']);
|
||||
}
|
||||
}
|
||||
130
app/Http/Controllers/Api/Admin/HeroSlideController.php
Normal file
130
app/Http/Controllers/Api/Admin/HeroSlideController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\HeroSlide\CreateHeroSlideAction;
|
||||
use App\Actions\HeroSlide\DeleteHeroSlideAction;
|
||||
use App\Actions\HeroSlide\UpdateHeroSlideAction;
|
||||
use App\DTOs\HeroSlideData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\HeroSlide\StoreHeroSlideRequest;
|
||||
use App\Http\Requests\HeroSlide\UpdateHeroSlideRequest;
|
||||
use App\Http\Resources\HeroSlideResource;
|
||||
use App\Models\HeroSlide;
|
||||
use App\Repositories\Contracts\HeroSlideRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class HeroSlideController extends Controller
|
||||
{
|
||||
public function __construct(private HeroSlideRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/hero-slides',
|
||||
summary: 'Hero slide listele (Admin)',
|
||||
tags: ['Admin - Hero Slides'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15))],
|
||||
responses: [new OA\Response(response: 200, description: 'Slide listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$slides = $this->repository->paginate(
|
||||
$request->only([]),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return HeroSlideResource::collection($slides);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/hero-slides',
|
||||
summary: 'Yeni hero slide oluştur',
|
||||
tags: ['Admin - Hero Slides'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['title', 'image'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'subtitle', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string'),
|
||||
new OA\Property(property: 'mobile_image', type: 'string'),
|
||||
new OA\Property(property: 'button_text', type: 'string'),
|
||||
new OA\Property(property: 'button_url', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Slide oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreHeroSlideRequest $request, CreateHeroSlideAction $action): JsonResponse
|
||||
{
|
||||
$dto = HeroSlideData::fromArray($request->validated());
|
||||
$slide = $action->execute($dto);
|
||||
|
||||
return response()->json(new HeroSlideResource($slide), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/hero-slides/{heroSlide}',
|
||||
summary: 'Hero slide detayı',
|
||||
tags: ['Admin - Hero Slides'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'heroSlide', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Slide detayı')],
|
||||
)]
|
||||
public function show(HeroSlide $heroSlide): JsonResponse
|
||||
{
|
||||
return response()->json(new HeroSlideResource($heroSlide));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/hero-slides/{heroSlide}',
|
||||
summary: 'Hero slide güncelle',
|
||||
tags: ['Admin - Hero Slides'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'heroSlide', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'subtitle', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string'),
|
||||
new OA\Property(property: 'button_text', type: 'string'),
|
||||
new OA\Property(property: 'button_url', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Slide güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateHeroSlideRequest $request, HeroSlide $heroSlide, UpdateHeroSlideAction $action): JsonResponse
|
||||
{
|
||||
$dto = HeroSlideData::fromArray(array_merge($heroSlide->toArray(), $request->validated()));
|
||||
$heroSlide = $action->execute($heroSlide, $dto);
|
||||
|
||||
return response()->json(new HeroSlideResource($heroSlide));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/hero-slides/{heroSlide}',
|
||||
summary: 'Hero slide sil',
|
||||
tags: ['Admin - Hero Slides'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'heroSlide', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Slide silindi')],
|
||||
)]
|
||||
public function destroy(HeroSlide $heroSlide, DeleteHeroSlideAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($heroSlide);
|
||||
|
||||
return response()->json(['message' => 'Hero slide silindi.']);
|
||||
}
|
||||
}
|
||||
103
app/Http/Controllers/Api/Admin/LeadController.php
Normal file
103
app/Http/Controllers/Api/Admin/LeadController.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Lead\DeleteLeadAction;
|
||||
use App\Actions\Lead\UpdateLeadAction;
|
||||
use App\DTOs\LeadData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Lead\UpdateLeadRequest;
|
||||
use App\Http\Resources\LeadResource;
|
||||
use App\Models\Lead;
|
||||
use App\Repositories\Contracts\LeadRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class LeadController extends Controller
|
||||
{
|
||||
public function __construct(private LeadRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/leads',
|
||||
summary: 'Başvuruları listele (Admin)',
|
||||
tags: ['Admin - Leads'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'status', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'source', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'is_read', in: 'query', required: false, schema: new OA\Schema(type: 'boolean')),
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Başvuru listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$leads = $this->repository->paginate(
|
||||
$request->only(['status', 'source', 'is_read', 'search']),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return LeadResource::collection($leads);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/leads/{lead}',
|
||||
summary: 'Başvuru detayı',
|
||||
tags: ['Admin - Leads'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'lead', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Başvuru detayı')],
|
||||
)]
|
||||
public function show(Lead $lead): JsonResponse
|
||||
{
|
||||
if (! $lead->is_read) {
|
||||
$lead->update(['is_read' => true]);
|
||||
}
|
||||
|
||||
return response()->json(new LeadResource($lead));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/leads/{lead}',
|
||||
summary: 'Başvuru güncelle',
|
||||
tags: ['Admin - Leads'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'lead', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'status', type: 'string'),
|
||||
new OA\Property(property: 'is_read', type: 'boolean'),
|
||||
new OA\Property(property: 'admin_notes', type: 'string'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Başvuru güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateLeadRequest $request, Lead $lead, UpdateLeadAction $action): JsonResponse
|
||||
{
|
||||
$dto = LeadData::fromArray(array_merge($lead->toArray(), $request->validated()));
|
||||
$lead = $action->execute($lead, $dto);
|
||||
|
||||
return response()->json(new LeadResource($lead));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/leads/{lead}',
|
||||
summary: 'Başvuru sil',
|
||||
tags: ['Admin - Leads'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'lead', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Başvuru silindi')],
|
||||
)]
|
||||
public function destroy(Lead $lead, DeleteLeadAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($lead);
|
||||
|
||||
return response()->json(['message' => 'Talep silindi.']);
|
||||
}
|
||||
}
|
||||
159
app/Http/Controllers/Api/Admin/MenuController.php
Normal file
159
app/Http/Controllers/Api/Admin/MenuController.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Menu\CreateMenuAction;
|
||||
use App\Actions\Menu\DeleteMenuAction;
|
||||
use App\Actions\Menu\UpdateMenuAction;
|
||||
use App\DTOs\MenuData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Menu\ReorderMenuRequest;
|
||||
use App\Http\Requests\Menu\StoreMenuRequest;
|
||||
use App\Http\Requests\Menu\UpdateMenuRequest;
|
||||
use App\Http\Resources\MenuResource;
|
||||
use App\Models\Menu;
|
||||
use App\Repositories\Contracts\MenuRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class MenuController extends Controller
|
||||
{
|
||||
public function __construct(private MenuRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/menus',
|
||||
summary: 'Menü öğelerini listele (Admin)',
|
||||
tags: ['Admin - Menus'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'location', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 50)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Menü listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$menus = $this->repository->paginate(
|
||||
$request->only(['location']),
|
||||
$request->integer('per_page', 50),
|
||||
);
|
||||
|
||||
return MenuResource::collection($menus);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/menus',
|
||||
summary: 'Yeni menü öğesi oluştur',
|
||||
tags: ['Admin - Menus'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['title', 'url', 'location'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'url', type: 'string'),
|
||||
new OA\Property(property: 'location', type: 'string'),
|
||||
new OA\Property(property: 'parent_id', type: 'integer'),
|
||||
new OA\Property(property: 'target', type: 'string'),
|
||||
new OA\Property(property: 'icon', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Menü oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreMenuRequest $request, CreateMenuAction $action): JsonResponse
|
||||
{
|
||||
$dto = MenuData::fromArray($request->validated());
|
||||
$menu = $action->execute($dto);
|
||||
|
||||
return response()->json(new MenuResource($menu), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/menus/{menu}',
|
||||
summary: 'Menü detayı',
|
||||
tags: ['Admin - Menus'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'menu', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Menü detayı')],
|
||||
)]
|
||||
public function show(Menu $menu): JsonResponse
|
||||
{
|
||||
return response()->json(new MenuResource($menu->load('children')));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/menus/{menu}',
|
||||
summary: 'Menü güncelle',
|
||||
tags: ['Admin - Menus'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'menu', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'url', type: 'string'),
|
||||
new OA\Property(property: 'location', type: 'string'),
|
||||
new OA\Property(property: 'parent_id', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'sort_order', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Menü güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateMenuRequest $request, Menu $menu, UpdateMenuAction $action): JsonResponse
|
||||
{
|
||||
$dto = MenuData::fromArray(array_merge($menu->toArray(), $request->validated()));
|
||||
$menu = $action->execute($menu, $dto);
|
||||
|
||||
return response()->json(new MenuResource($menu->load('children')));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/menus/{menu}',
|
||||
summary: 'Menü sil',
|
||||
tags: ['Admin - Menus'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'menu', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Menü silindi')],
|
||||
)]
|
||||
public function destroy(Menu $menu, DeleteMenuAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($menu);
|
||||
|
||||
return response()->json(['message' => 'Menü silindi.']);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/menus/reorder',
|
||||
summary: 'Menü sıralamasını güncelle',
|
||||
tags: ['Admin - Menus'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['items'],
|
||||
properties: [
|
||||
new OA\Property(property: 'items', type: 'array', items: new OA\Items(
|
||||
properties: [
|
||||
new OA\Property(property: 'id', type: 'integer'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'parent_id', type: 'integer', nullable: true),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
responses: [new OA\Response(response: 200, description: 'Sıralama güncellendi')],
|
||||
)]
|
||||
public function reorder(ReorderMenuRequest $request): JsonResponse
|
||||
{
|
||||
$this->repository->reorder($request->validated('items'));
|
||||
|
||||
return response()->json(['message' => 'Menü sıralaması güncellendi.']);
|
||||
}
|
||||
}
|
||||
179
app/Http/Controllers/Api/Admin/PageController.php
Normal file
179
app/Http/Controllers/Api/Admin/PageController.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Page\CreatePageAction;
|
||||
use App\Actions\Page\DeletePageAction;
|
||||
use App\Actions\Page\UpdatePageAction;
|
||||
use App\DTOs\PageData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Page\StorePageRequest;
|
||||
use App\Http\Requests\Page\UpdatePageRequest;
|
||||
use App\Http\Resources\PageResource;
|
||||
use App\Models\Page;
|
||||
use App\Repositories\Contracts\PageRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class PageController extends Controller
|
||||
{
|
||||
public function __construct(private PageRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/pages',
|
||||
summary: 'Sayfaları listele (Admin)',
|
||||
tags: ['Admin - Pages'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Sayfa listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$pages = $this->repository->paginate(
|
||||
$request->only(['search']),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return PageResource::collection($pages);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/pages',
|
||||
summary: 'Yeni sayfa oluştur',
|
||||
tags: ['Admin - Pages'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['title', 'slug'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'slug', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'string'),
|
||||
new OA\Property(property: 'template', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'meta_title', type: 'string'),
|
||||
new OA\Property(property: 'meta_description', type: 'string'),
|
||||
new OA\Property(property: 'blocks', type: 'array', items: new OA\Items(
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Sayfa oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StorePageRequest $request, CreatePageAction $action): JsonResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $action) {
|
||||
$validated = $request->validated();
|
||||
$blocks = $validated['blocks'] ?? [];
|
||||
unset($validated['blocks']);
|
||||
|
||||
$dto = PageData::fromArray($validated);
|
||||
$page = $action->execute($dto);
|
||||
|
||||
foreach ($blocks as $index => $block) {
|
||||
$page->blocks()->create([
|
||||
'type' => $block['type'],
|
||||
'content' => $block['content'],
|
||||
'order_index' => $block['order_index'] ?? $index,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json(new PageResource($page->load('blocks')), 201);
|
||||
});
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/pages/{page}',
|
||||
summary: 'Sayfa detayı (Admin)',
|
||||
tags: ['Admin - Pages'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Sayfa detayı')],
|
||||
)]
|
||||
public function show(Page $page): JsonResponse
|
||||
{
|
||||
return response()->json(new PageResource($page->load('blocks')));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/pages/{page}',
|
||||
summary: 'Sayfa güncelle',
|
||||
tags: ['Admin - Pages'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'slug', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'string'),
|
||||
new OA\Property(property: 'template', type: 'string'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
new OA\Property(property: 'meta_title', type: 'string'),
|
||||
new OA\Property(property: 'meta_description', type: 'string'),
|
||||
new OA\Property(property: 'blocks', type: 'array', items: new OA\Items(
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Sayfa güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdatePageRequest $request, Page $page, UpdatePageAction $action): JsonResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $page, $action) {
|
||||
$validated = $request->validated();
|
||||
$blocks = $validated['blocks'] ?? null;
|
||||
unset($validated['blocks']);
|
||||
|
||||
$dto = PageData::fromArray(array_merge($page->toArray(), $validated));
|
||||
$page = $action->execute($page, $dto);
|
||||
|
||||
if ($blocks !== null) {
|
||||
$page->blocks()->delete();
|
||||
foreach ($blocks as $index => $block) {
|
||||
$page->blocks()->create([
|
||||
'type' => $block['type'],
|
||||
'content' => $block['content'],
|
||||
'order_index' => $block['order_index'] ?? $index,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(new PageResource($page->load('blocks')));
|
||||
});
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/pages/{page}',
|
||||
summary: 'Sayfa sil',
|
||||
tags: ['Admin - Pages'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'page', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Sayfa silindi')],
|
||||
)]
|
||||
public function destroy(Page $page, DeletePageAction $action): JsonResponse
|
||||
{
|
||||
$page->blocks()->delete();
|
||||
$action->execute($page);
|
||||
|
||||
return response()->json(['message' => 'Sayfa silindi.']);
|
||||
}
|
||||
}
|
||||
92
app/Http/Controllers/Api/Admin/PreviewController.php
Normal file
92
app/Http/Controllers/Api/Admin/PreviewController.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Preview\StorePreviewRequest;
|
||||
use App\Models\Page;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class PreviewController extends Controller
|
||||
{
|
||||
private const CACHE_TTL = 600; // 10 minutes
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/preview',
|
||||
summary: 'Önizleme oluştur',
|
||||
tags: ['Admin - Preview'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['page_id', 'blocks'],
|
||||
properties: [
|
||||
new OA\Property(property: 'page_id', type: 'integer'),
|
||||
new OA\Property(property: 'blocks', type: 'array', items: new OA\Items(
|
||||
properties: [
|
||||
new OA\Property(property: 'type', type: 'string'),
|
||||
new OA\Property(property: 'content', type: 'object'),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Önizleme oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StorePreviewRequest $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$page = Page::findOrFail($validated['page_id']);
|
||||
$token = (string) Str::uuid();
|
||||
|
||||
$blocks = collect($validated['blocks'])
|
||||
->sortBy('order_index')
|
||||
->values()
|
||||
->map(fn (array $block, int $index) => [
|
||||
'id' => $index + 1,
|
||||
'type' => $block['type'],
|
||||
'content' => $block['content'],
|
||||
'order_index' => $block['order_index'],
|
||||
])
|
||||
->all();
|
||||
|
||||
Cache::put("preview_{$token}", [
|
||||
'id' => $page->id,
|
||||
'slug' => $page->slug,
|
||||
'title' => $page->title,
|
||||
'meta_title' => $page->meta_title,
|
||||
'meta_description' => $page->meta_description,
|
||||
'is_active' => $page->is_active,
|
||||
'blocks' => $blocks,
|
||||
'created_at' => $page->created_at?->toISOString(),
|
||||
'updated_at' => now()->toISOString(),
|
||||
], self::CACHE_TTL);
|
||||
|
||||
$previewUrl = config('app.frontend_url')."/api/preview?token={$token}&slug={$page->slug}";
|
||||
|
||||
return response()->json([
|
||||
'token' => $token,
|
||||
'preview_url' => $previewUrl,
|
||||
'expires_in' => self::CACHE_TTL,
|
||||
], 201);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/preview/{token}',
|
||||
summary: 'Önizlemeyi sil',
|
||||
tags: ['Admin - Preview'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'token', in: 'path', required: true, schema: new OA\Schema(type: 'string'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Önizleme silindi')],
|
||||
)]
|
||||
public function destroy(string $token): JsonResponse
|
||||
{
|
||||
Cache::forget("preview_{$token}");
|
||||
|
||||
return response()->json(['message' => 'Önizleme silindi.']);
|
||||
}
|
||||
}
|
||||
180
app/Http/Controllers/Api/Admin/RoleController.php
Normal file
180
app/Http/Controllers/Api/Admin/RoleController.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Role\StoreRoleRequest;
|
||||
use App\Http\Requests\Role\UpdateRoleRequest;
|
||||
use App\Http\Resources\RoleResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class RoleController extends Controller
|
||||
{
|
||||
#[OA\Get(
|
||||
path: '/api/admin/roles',
|
||||
summary: 'Rolleri listele',
|
||||
tags: ['Admin - Roles'],
|
||||
security: [['sanctum' => []]],
|
||||
responses: [new OA\Response(response: 200, description: 'Rol listesi')],
|
||||
)]
|
||||
public function index(): AnonymousResourceCollection
|
||||
{
|
||||
$roles = Role::query()
|
||||
->with('permissions')
|
||||
->get()
|
||||
->loadCount('users');
|
||||
|
||||
return RoleResource::collection($roles);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/roles',
|
||||
summary: 'Yeni rol oluştur',
|
||||
tags: ['Admin - Roles'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['name', 'permissions'],
|
||||
properties: [
|
||||
new OA\Property(property: 'name', type: 'string', example: 'moderator'),
|
||||
new OA\Property(property: 'permissions', type: 'array', items: new OA\Items(type: 'string'), example: ['view-category', 'view-course']),
|
||||
],
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Rol oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreRoleRequest $request): JsonResponse
|
||||
{
|
||||
$role = Role::create([
|
||||
'name' => $request->validated('name'),
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
|
||||
$role->syncPermissions($request->validated('permissions'));
|
||||
$role->load('permissions');
|
||||
|
||||
return (new RoleResource($role))
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/roles/{role}',
|
||||
summary: 'Rol detayı',
|
||||
tags: ['Admin - Roles'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'role', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Rol detayı'),
|
||||
new OA\Response(response: 404, description: 'Bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function show(Role $role): RoleResource
|
||||
{
|
||||
$role->load('permissions');
|
||||
$role->loadCount('users');
|
||||
|
||||
return new RoleResource($role);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/roles/{role}',
|
||||
summary: 'Rol güncelle',
|
||||
tags: ['Admin - Roles'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'role', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'name', type: 'string', example: 'moderator'),
|
||||
new OA\Property(property: 'permissions', type: 'array', items: new OA\Items(type: 'string')),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Rol güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateRoleRequest $request, Role $role): RoleResource
|
||||
{
|
||||
$validated = $request->validated();
|
||||
|
||||
if (isset($validated['name'])) {
|
||||
$role->update(['name' => $validated['name']]);
|
||||
}
|
||||
|
||||
if (isset($validated['permissions'])) {
|
||||
$role->syncPermissions($validated['permissions']);
|
||||
}
|
||||
|
||||
$role->load('permissions');
|
||||
|
||||
return new RoleResource($role);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/roles/{role}',
|
||||
summary: 'Rol sil',
|
||||
tags: ['Admin - Roles'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'role', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Rol silindi'),
|
||||
new OA\Response(response: 403, description: 'Varsayılan roller silinemez'),
|
||||
new OA\Response(response: 404, description: 'Bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function destroy(Role $role): JsonResponse
|
||||
{
|
||||
if (in_array($role->name, ['super-admin', 'editor'])) {
|
||||
return response()->json(['message' => 'Varsayılan roller silinemez.'], 403);
|
||||
}
|
||||
|
||||
if ($role->users()->count() > 0) {
|
||||
return response()->json(['message' => 'Bu role atanmış kullanıcılar var. Önce kullanıcıların rollerini değiştirin.'], 422);
|
||||
}
|
||||
|
||||
$role->delete();
|
||||
|
||||
return response()->json(['message' => 'Rol başarıyla silindi.']);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/permissions',
|
||||
summary: 'Tüm yetkileri listele',
|
||||
description: 'Rol oluştururken/düzenlerken kullanılacak tüm mevcut yetkileri modül bazlı gruplandırarak döner.',
|
||||
tags: ['Admin - Roles'],
|
||||
security: [['sanctum' => []]],
|
||||
responses: [new OA\Response(response: 200, description: 'Yetki listesi')],
|
||||
)]
|
||||
public function permissions(): JsonResponse
|
||||
{
|
||||
$permissions = Permission::query()
|
||||
->where('guard_name', 'web')
|
||||
->orderBy('name')
|
||||
->pluck('name');
|
||||
|
||||
// Modül bazlı gruplandırma
|
||||
$grouped = [];
|
||||
foreach ($permissions as $permission) {
|
||||
$parts = explode('-', $permission, 2);
|
||||
if (count($parts) === 2) {
|
||||
$grouped[$parts[1]][] = $permission;
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'all' => $permissions,
|
||||
'grouped' => $grouped,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
135
app/Http/Controllers/Api/Admin/ScheduleController.php
Normal file
135
app/Http/Controllers/Api/Admin/ScheduleController.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Schedule\CreateScheduleAction;
|
||||
use App\Actions\Schedule\DeleteScheduleAction;
|
||||
use App\Actions\Schedule\UpdateScheduleAction;
|
||||
use App\DTOs\ScheduleData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Schedule\StoreScheduleRequest;
|
||||
use App\Http\Requests\Schedule\UpdateScheduleRequest;
|
||||
use App\Http\Resources\CourseScheduleResource;
|
||||
use App\Models\CourseSchedule;
|
||||
use App\Repositories\Contracts\ScheduleRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class ScheduleController extends Controller
|
||||
{
|
||||
public function __construct(private ScheduleRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/schedules',
|
||||
summary: 'Takvimleri listele (Admin)',
|
||||
tags: ['Admin - Schedules'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'course_id', in: 'query', required: false, schema: new OA\Schema(type: 'integer')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Takvim listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$schedules = $this->repository->paginate(
|
||||
$request->only(['course_id']),
|
||||
$request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return CourseScheduleResource::collection($schedules);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/schedules',
|
||||
summary: 'Yeni takvim oluştur',
|
||||
tags: ['Admin - Schedules'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['course_id', 'start_date', 'location', 'quota'],
|
||||
properties: [
|
||||
new OA\Property(property: 'course_id', type: 'integer'),
|
||||
new OA\Property(property: 'start_date', type: 'string', format: 'date'),
|
||||
new OA\Property(property: 'end_date', type: 'string', format: 'date'),
|
||||
new OA\Property(property: 'location', type: 'string'),
|
||||
new OA\Property(property: 'instructor', type: 'string'),
|
||||
new OA\Property(property: 'quota', type: 'integer'),
|
||||
new OA\Property(property: 'enrolled_count', type: 'integer'),
|
||||
new OA\Property(property: 'price_override', type: 'number'),
|
||||
new OA\Property(property: 'status', type: 'string'),
|
||||
new OA\Property(property: 'notes', type: 'string'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Takvim oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreScheduleRequest $request, CreateScheduleAction $action): JsonResponse
|
||||
{
|
||||
$dto = ScheduleData::fromArray($request->validated());
|
||||
$schedule = $action->execute($dto);
|
||||
|
||||
return response()->json(new CourseScheduleResource($schedule->load('course')), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/schedules/{schedule}',
|
||||
summary: 'Takvim detayı (Admin)',
|
||||
tags: ['Admin - Schedules'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'schedule', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Takvim detayı')],
|
||||
)]
|
||||
public function show(CourseSchedule $schedule): JsonResponse
|
||||
{
|
||||
return response()->json(new CourseScheduleResource($schedule->load('course')));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/schedules/{schedule}',
|
||||
summary: 'Takvim güncelle',
|
||||
tags: ['Admin - Schedules'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'schedule', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'course_id', type: 'integer'),
|
||||
new OA\Property(property: 'start_date', type: 'string', format: 'date'),
|
||||
new OA\Property(property: 'end_date', type: 'string', format: 'date'),
|
||||
new OA\Property(property: 'location', type: 'string'),
|
||||
new OA\Property(property: 'instructor', type: 'string'),
|
||||
new OA\Property(property: 'quota', type: 'integer'),
|
||||
new OA\Property(property: 'status', type: 'string'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Takvim güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateScheduleRequest $request, CourseSchedule $schedule, UpdateScheduleAction $action): JsonResponse
|
||||
{
|
||||
$dto = ScheduleData::fromArray(array_merge($schedule->toArray(), $request->validated()));
|
||||
$schedule = $action->execute($schedule, $dto);
|
||||
|
||||
return response()->json(new CourseScheduleResource($schedule->load('course')));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/schedules/{schedule}',
|
||||
summary: 'Takvim sil',
|
||||
tags: ['Admin - Schedules'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'schedule', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Takvim silindi')],
|
||||
)]
|
||||
public function destroy(CourseSchedule $schedule, DeleteScheduleAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($schedule);
|
||||
|
||||
return response()->json(['message' => 'Takvim silindi.']);
|
||||
}
|
||||
}
|
||||
89
app/Http/Controllers/Api/Admin/SettingController.php
Normal file
89
app/Http/Controllers/Api/Admin/SettingController.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\Setting\UpdateSettingsAction;
|
||||
use App\Enums\SettingGroup;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Setting\UpdateSettingsRequest;
|
||||
use App\Http\Resources\SettingResource;
|
||||
use App\Repositories\Contracts\SettingRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
public function __construct(private SettingRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/settings',
|
||||
summary: 'Tüm ayarları listele (Admin)',
|
||||
tags: ['Admin - Settings'],
|
||||
security: [['sanctum' => []]],
|
||||
responses: [new OA\Response(response: 200, description: 'Ayar listesi')],
|
||||
)]
|
||||
public function index(): AnonymousResourceCollection
|
||||
{
|
||||
return SettingResource::collection($this->repository->all());
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/settings/group/{group}',
|
||||
summary: 'Gruba göre ayarları getir',
|
||||
tags: ['Admin - Settings'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'group', in: 'path', required: true, schema: new OA\Schema(type: 'string'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Grup ayarları'),
|
||||
new OA\Response(response: 404, description: 'Grup bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function group(string $group): AnonymousResourceCollection
|
||||
{
|
||||
$settingGroup = SettingGroup::tryFrom($group);
|
||||
|
||||
if (! $settingGroup) {
|
||||
abort(404, 'Ayar grubu bulunamadı.');
|
||||
}
|
||||
|
||||
return SettingResource::collection($this->repository->getByGroup($settingGroup));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/settings',
|
||||
summary: 'Ayarları toplu güncelle (dot notation: general.site_name)',
|
||||
tags: ['Admin - Settings'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['settings'],
|
||||
properties: [
|
||||
new OA\Property(property: 'settings', type: 'object', example: '{"general.site_name": "Yeni Ad", "contact.phone_primary": "+90 ..."}'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Ayarlar güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateSettingsRequest $request, UpdateSettingsAction $action): JsonResponse
|
||||
{
|
||||
$action->execute($request->validated('settings'));
|
||||
|
||||
return response()->json(['message' => 'Ayarlar güncellendi.']);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/settings/clear-cache',
|
||||
summary: 'Ayar cache temizle',
|
||||
tags: ['Admin - Settings'],
|
||||
security: [['sanctum' => []]],
|
||||
responses: [new OA\Response(response: 200, description: 'Cache temizlendi')],
|
||||
)]
|
||||
public function clearCache(): JsonResponse
|
||||
{
|
||||
$this->repository->clearCache();
|
||||
|
||||
return response()->json(['message' => 'Ayar cache temizlendi.']);
|
||||
}
|
||||
}
|
||||
138
app/Http/Controllers/Api/Admin/StoryController.php
Normal file
138
app/Http/Controllers/Api/Admin/StoryController.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\StoryResource;
|
||||
use App\Models\Story;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class StoryController extends Controller
|
||||
{
|
||||
#[OA\Get(
|
||||
path: '/api/admin/stories',
|
||||
summary: 'Tüm hikayeleri listele (Admin)',
|
||||
tags: ['Admin - Stories'],
|
||||
security: [['sanctum' => []]],
|
||||
responses: [new OA\Response(response: 200, description: 'Hikaye listesi')],
|
||||
)]
|
||||
public function index(): AnonymousResourceCollection
|
||||
{
|
||||
return StoryResource::collection(
|
||||
Story::query()->orderBy('order_index')->get()
|
||||
);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/stories',
|
||||
summary: 'Yeni hikaye oluştur',
|
||||
tags: ['Admin - Stories'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['title', 'content'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'badge', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'content', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'cta_text', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'cta_url', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Hikaye oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'title' => ['required', 'string', 'max:255'],
|
||||
'badge' => ['nullable', 'string', 'max:100'],
|
||||
'content' => ['required', 'string'],
|
||||
'image' => ['nullable', 'string', 'max:255'],
|
||||
'cta_text' => ['nullable', 'string', 'max:100'],
|
||||
'cta_url' => ['nullable', 'string', 'max:255'],
|
||||
'order_index' => ['sometimes', 'integer', 'min:0'],
|
||||
'is_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$story = Story::create($validated);
|
||||
|
||||
return response()->json(new StoryResource($story), 201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/stories/{story}',
|
||||
summary: 'Hikaye detayı',
|
||||
tags: ['Admin - Stories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'story', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Hikaye detayı')],
|
||||
)]
|
||||
public function show(Story $story): JsonResponse
|
||||
{
|
||||
return response()->json(new StoryResource($story));
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/stories/{story}',
|
||||
summary: 'Hikaye güncelle',
|
||||
tags: ['Admin - Stories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'story', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', type: 'string'),
|
||||
new OA\Property(property: 'badge', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'content', type: 'string'),
|
||||
new OA\Property(property: 'image', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'cta_text', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'cta_url', type: 'string', nullable: true),
|
||||
new OA\Property(property: 'order_index', type: 'integer'),
|
||||
new OA\Property(property: 'is_active', type: 'boolean'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Hikaye güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(Request $request, Story $story): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'title' => ['sometimes', 'string', 'max:255'],
|
||||
'badge' => ['nullable', 'string', 'max:100'],
|
||||
'content' => ['sometimes', 'string'],
|
||||
'image' => ['nullable', 'string', 'max:255'],
|
||||
'cta_text' => ['nullable', 'string', 'max:100'],
|
||||
'cta_url' => ['nullable', 'string', 'max:255'],
|
||||
'order_index' => ['sometimes', 'integer', 'min:0'],
|
||||
'is_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$story->update($validated);
|
||||
|
||||
return response()->json(new StoryResource($story->fresh()));
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/stories/{story}',
|
||||
summary: 'Hikaye sil',
|
||||
tags: ['Admin - Stories'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'story', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [new OA\Response(response: 200, description: 'Hikaye silindi')],
|
||||
)]
|
||||
public function destroy(Story $story): JsonResponse
|
||||
{
|
||||
$story->delete();
|
||||
|
||||
return response()->json(['message' => 'Hikaye silindi.']);
|
||||
}
|
||||
}
|
||||
138
app/Http/Controllers/Api/Admin/UploadController.php
Normal file
138
app/Http/Controllers/Api/Admin/UploadController.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class UploadController extends Controller
|
||||
{
|
||||
#[OA\Post(
|
||||
path: '/api/admin/upload',
|
||||
summary: 'Dosya yükle',
|
||||
description: 'Görsel veya video dosyası yükler. Görseller max 5MB, videolar max 100MB. Modül bazlı klasörleme destekler.',
|
||||
security: [['sanctum' => []]],
|
||||
tags: ['Upload'],
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\MediaType(
|
||||
mediaType: 'multipart/form-data',
|
||||
schema: new OA\Schema(
|
||||
required: ['file'],
|
||||
properties: [
|
||||
new OA\Property(property: 'file', type: 'string', format: 'binary', description: 'Görsel veya video dosyası'),
|
||||
new OA\Property(property: 'type', type: 'string', enum: ['image', 'video'], description: 'Dosya tipi'),
|
||||
new OA\Property(property: 'folder', type: 'string', description: 'Modül klasörü (hero-slides, courses, vb.)'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Dosya yüklendi', content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'data', type: 'object', properties: [
|
||||
new OA\Property(property: 'path', type: 'string'),
|
||||
new OA\Property(property: 'url', type: 'string'),
|
||||
]),
|
||||
],
|
||||
)),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$type = $request->input('type', 'image');
|
||||
|
||||
if ($type === 'video') {
|
||||
return $this->storeVideo($request);
|
||||
}
|
||||
|
||||
return $this->storeImage($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private const ALLOWED_FOLDERS = [
|
||||
'images',
|
||||
'videos',
|
||||
'hero-slides',
|
||||
'settings',
|
||||
'pages',
|
||||
'courses',
|
||||
'announcements',
|
||||
'categories',
|
||||
];
|
||||
|
||||
private function resolveFolder(Request $request, string $default): string
|
||||
{
|
||||
$folder = $request->input('folder', $default);
|
||||
|
||||
if (! in_array($folder, self::ALLOWED_FOLDERS, true)) {
|
||||
$folder = $default;
|
||||
}
|
||||
|
||||
return $folder;
|
||||
}
|
||||
|
||||
private function storeImage(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'file' => ['required', 'file', 'image', 'max:5120'],
|
||||
'folder' => ['sometimes', 'string'],
|
||||
], [
|
||||
'file.required' => 'Dosya zorunludur.',
|
||||
'file.image' => 'Dosya bir görsel (jpg, png, gif, svg, webp) olmalıdır.',
|
||||
'file.max' => 'Dosya boyutu en fazla 5MB olabilir.',
|
||||
]);
|
||||
|
||||
$folder = $this->resolveFolder($request, 'images');
|
||||
|
||||
$file = $request->file('file');
|
||||
$filename = Str::uuid().'.'.$file->getClientOriginalExtension();
|
||||
|
||||
$directory = public_path('uploads/'.$folder);
|
||||
$file->move($directory, $filename);
|
||||
|
||||
$relativePath = 'uploads/'.$folder.'/'.$filename;
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'path' => $relativePath,
|
||||
'url' => url($relativePath),
|
||||
],
|
||||
], 201);
|
||||
}
|
||||
|
||||
private function storeVideo(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'file' => ['required', 'file', 'mimes:mp4,webm,mov,avi,mkv', 'max:102400'],
|
||||
'folder' => ['sometimes', 'string'],
|
||||
], [
|
||||
'file.required' => 'Dosya zorunludur.',
|
||||
'file.mimes' => 'Dosya bir video (mp4, webm, mov, avi, mkv) olmalıdır.',
|
||||
'file.max' => 'Video boyutu en fazla 100MB olabilir.',
|
||||
]);
|
||||
|
||||
$folder = $this->resolveFolder($request, 'videos');
|
||||
|
||||
$file = $request->file('file');
|
||||
$filename = Str::uuid().'.'.$file->getClientOriginalExtension();
|
||||
|
||||
$directory = public_path('uploads/'.$folder);
|
||||
$file->move($directory, $filename);
|
||||
|
||||
$relativePath = 'uploads/'.$folder.'/'.$filename;
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'path' => $relativePath,
|
||||
'url' => url($relativePath),
|
||||
],
|
||||
], 201);
|
||||
}
|
||||
}
|
||||
147
app/Http/Controllers/Api/Admin/UserController.php
Normal file
147
app/Http/Controllers/Api/Admin/UserController.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Actions\User\CreateUserAction;
|
||||
use App\Actions\User\DeleteUserAction;
|
||||
use App\Actions\User\UpdateUserAction;
|
||||
use App\DTOs\UserData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\User\StoreUserRequest;
|
||||
use App\Http\Requests\User\UpdateUserRequest;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Models\User;
|
||||
use App\Repositories\Contracts\UserRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function __construct(private UserRepositoryInterface $repository) {}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/users',
|
||||
summary: 'Admin kullanıcılarını listele',
|
||||
tags: ['Admin - Users'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'role', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15)),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Kullanıcı listesi')],
|
||||
)]
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$users = $this->repository->paginate(
|
||||
filters: $request->only('search', 'role'),
|
||||
perPage: $request->integer('per_page', 15),
|
||||
);
|
||||
|
||||
return UserResource::collection($users);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/admin/users',
|
||||
summary: 'Yeni admin kullanıcı oluştur',
|
||||
tags: ['Admin - Users'],
|
||||
security: [['sanctum' => []]],
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['name', 'email', 'password', 'password_confirmation', 'role'],
|
||||
properties: [
|
||||
new OA\Property(property: 'name', type: 'string', example: 'Editör Kullanıcı'),
|
||||
new OA\Property(property: 'email', type: 'string', format: 'email', example: 'editor@bogazici.com'),
|
||||
new OA\Property(property: 'password', type: 'string', format: 'password', example: 'password123'),
|
||||
new OA\Property(property: 'password_confirmation', type: 'string', format: 'password', example: 'password123'),
|
||||
new OA\Property(property: 'role', type: 'string', example: 'editor'),
|
||||
],
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new OA\Response(response: 201, description: 'Kullanıcı oluşturuldu'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function store(StoreUserRequest $request, CreateUserAction $action): JsonResponse
|
||||
{
|
||||
$dto = UserData::fromArray($request->validated());
|
||||
$user = $action->execute($dto);
|
||||
|
||||
return (new UserResource($user))
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/admin/users/{user}',
|
||||
summary: 'Kullanıcı detayı',
|
||||
tags: ['Admin - Users'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'user', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kullanıcı detayı'),
|
||||
new OA\Response(response: 404, description: 'Bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function show(User $user): UserResource
|
||||
{
|
||||
$user->load('roles');
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/api/admin/users/{user}',
|
||||
summary: 'Kullanıcı güncelle',
|
||||
tags: ['Admin - Users'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'user', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'name', type: 'string'),
|
||||
new OA\Property(property: 'email', type: 'string', format: 'email'),
|
||||
new OA\Property(property: 'password', type: 'string', format: 'password'),
|
||||
new OA\Property(property: 'password_confirmation', type: 'string', format: 'password'),
|
||||
new OA\Property(property: 'role', type: 'string', example: 'editor'),
|
||||
],
|
||||
)),
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kullanıcı güncellendi'),
|
||||
new OA\Response(response: 422, description: 'Validasyon hatası'),
|
||||
],
|
||||
)]
|
||||
public function update(UpdateUserRequest $request, User $user, UpdateUserAction $action): UserResource
|
||||
{
|
||||
$dto = UserData::fromArray($request->validated());
|
||||
$user = $action->execute($user, $dto);
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/api/admin/users/{user}',
|
||||
summary: 'Kullanıcı sil (soft delete)',
|
||||
tags: ['Admin - Users'],
|
||||
security: [['sanctum' => []]],
|
||||
parameters: [new OA\Parameter(name: 'user', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Kullanıcı silindi'),
|
||||
new OA\Response(response: 403, description: 'Kendini silemezsin'),
|
||||
new OA\Response(response: 404, description: 'Bulunamadı'),
|
||||
],
|
||||
)]
|
||||
public function destroy(User $user, DeleteUserAction $action): JsonResponse
|
||||
{
|
||||
if ($user->id === auth()->id()) {
|
||||
return response()->json(['message' => 'Kendinizi silemezsiniz.'], 403);
|
||||
}
|
||||
|
||||
$action->execute($user);
|
||||
|
||||
return response()->json(['message' => 'Kullanıcı başarıyla silindi.']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user