Restore local changes after Git corruption
This commit is contained in:
37
app/Http/Controllers/AiController.php
Normal file
37
app/Http/Controllers/AiController.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\AiSuggestorService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AiController extends Controller
|
||||
{
|
||||
public function suggest(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'task_id' => 'nullable|integer',
|
||||
'custom_prompt' => 'nullable|string',
|
||||
'budget' => 'nullable|numeric|min:0',
|
||||
]);
|
||||
|
||||
try {
|
||||
$service = new AiSuggestorService();
|
||||
$result = $service->suggest(
|
||||
$request->input('task_id'), // ✅ Безопасно: вернёт null, если нет
|
||||
$request->input('custom_prompt'),
|
||||
$request->input('budget')
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Сборка успешно сгенерирована ИИ.',
|
||||
'build' => $result['build']->load('components'),
|
||||
], 201);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'message' => 'Не удалось сгенерировать сборку.',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
app/Http/Controllers/AuthController.php
Normal file
74
app/Http/Controllers/AuthController.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* Регистрация пользователя.
|
||||
*/
|
||||
public function register(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|string|email|max:255|unique:users',
|
||||
'password' => 'required|string|min:8|confirmed',
|
||||
'custom_field' => 'required|string|min:2'
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $validated['name'],
|
||||
'email' => $validated['email'],
|
||||
'password' => Hash::make($validated['password']),
|
||||
'custom_field' => $validated['custom_field'],
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Пользователь зарегистрирован.',
|
||||
'user' => $user,
|
||||
'token' => $user->createToken('auth_token')->plainTextToken
|
||||
], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Вход пользователя.
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'password' => 'required',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (!$user || !Hash::check($request->password, $user->password)) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => ['Неверные учётные данные.'],
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Успешный вход.',
|
||||
'user' => $user,
|
||||
'token' => $user->createToken('auth_token')->plainTextToken
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Выход (инвалидация токена).
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$request->user()->currentAccessToken()->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Вы успешно вышли из системы.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,15 @@ use Illuminate\Http\Response;
|
||||
|
||||
class ComponentsController extends Controller
|
||||
{
|
||||
public function index(){
|
||||
return response()->json(Component::all()->toJson());
|
||||
}
|
||||
public function index()
|
||||
{
|
||||
$components = Component::with('user', 'componentType')
|
||||
->where('is_official', true)
|
||||
->orWhere('created_by_user_id', auth()->id())
|
||||
->get();
|
||||
|
||||
return response()->json($components);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,49 +32,73 @@ class ComponentsController extends Controller
|
||||
return response()->json($component);
|
||||
}
|
||||
|
||||
public function create(Request $request)
|
||||
{
|
||||
$name = $request->get(key:'name');
|
||||
$type = $request->get(key:'type');
|
||||
$brand = $request->get(key:'brand');
|
||||
$model = $request->get(key:'model');
|
||||
$price = $request->get(key:'price');
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'price' => 'required|numeric|min:0',
|
||||
'component_type_id' => 'required|exists:component_types,id',
|
||||
'specifications' => 'nullable|array',
|
||||
]);
|
||||
|
||||
$component = new Component();
|
||||
$component->name = $name;
|
||||
$component->type = $type;
|
||||
$component->brand = $brand;
|
||||
$component->model = $model;
|
||||
$component->price = $price;
|
||||
|
||||
$component->save();
|
||||
$component = Component::create([
|
||||
'name' => $validated['name'],
|
||||
'price' => $validated['price'],
|
||||
'component_type_id' => $validated['component_type_id'],
|
||||
'specifications' => $validated['specifications'] ?? null,
|
||||
'is_official' => false, // всегда false для пользователя
|
||||
'created_by_user_id' => auth()->id(), // автоматически привязываем к пользователю
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Компонент успешно создан.',
|
||||
'component' => $component
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$component = Component::findOrFail($id);
|
||||
|
||||
|
||||
return response()->json($component->toJson());
|
||||
// Проверяем, что компонент принадлежит пользователю и не официальный
|
||||
if ($component->created_by_user_id !== auth()->id() || $component->is_official) {
|
||||
return response()->json([
|
||||
'message' => 'Вы не можете редактировать этот компонент.'
|
||||
], 403);
|
||||
}
|
||||
|
||||
public function update(Request $request, int $id): JsonResponse{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'price' => 'required|numeric|min:0',
|
||||
'component_type_id' => 'required|exists:component_types,id',
|
||||
'specifications' => 'nullable|array',
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'name' => $request->get('name'),
|
||||
'type' => $request->get('type'),
|
||||
'brand' => $request->get('brand'),
|
||||
'model' => $request->get('model'),
|
||||
'price' => $request->get('price'),
|
||||
], Response::HTTP_ACCEPTED);
|
||||
|
||||
}
|
||||
$component->update($validated);
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
// мы бы здесь написали вызов запроса delete из БД
|
||||
return response()->json([
|
||||
'message' => 'Компонент обновлён.',
|
||||
'component' => $component
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$component = Component::findOrFail($id);
|
||||
|
||||
// Проверяем, что компонент принадлежит пользователю и не официальный
|
||||
if ($component->created_by_user_id !== auth()->id() || $component->is_official) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
], Response::HTTP_ACCEPTED);
|
||||
'message' => 'Вы не можете удалить этот компонент.'
|
||||
], 403);
|
||||
}
|
||||
|
||||
|
||||
$component->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Компонент удалён.'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
246
app/Http/Controllers/PCBuildsController.php
Normal file
246
app/Http/Controllers/PCBuildsController.php
Normal file
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\PCBuild;
|
||||
use App\Models\Component;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\BuildValidator;
|
||||
|
||||
class PCBuildsController extends Controller
|
||||
{
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/builds",
|
||||
* summary="Получить список своих сборок",
|
||||
* tags={"PC Builds"},
|
||||
* @OA\Response(response=200, description="Список сборок"),
|
||||
* @OA\Response(response=401, description="Неавторизован")
|
||||
* )
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$builds = PCBuild::where('user_id', auth()->id())
|
||||
->with('components')
|
||||
->get();
|
||||
|
||||
return response()->json($builds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/builds",
|
||||
* summary="Создать новую сборку",
|
||||
* tags={"PC Builds"},
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
* @OA\JsonContent(
|
||||
* required={"name", "component_ids"},
|
||||
* @OA\Property(property="name", type="string", example="Игровой ПК 2025"),
|
||||
* @OA\Property(property="description", type="string", nullable=true, example="Для игр в 1440p"),
|
||||
* @OA\Property(property="component_ids", type="array", @OA\Items(type="integer", example=1)),
|
||||
* @OA\Property(property="is_ai_generated", type="boolean", default=false),
|
||||
* @OA\Property(property="ai_prompt", type="string", nullable=true, example="Сборка до 1000$ для игр")
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(response=201, description="Сборка создана"),
|
||||
* @OA\Response(response=400, description="Ошибка валидации"),
|
||||
* @OA\Response(response=403, description="Запрещено: чужие компоненты")
|
||||
* )
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'component_ids' => 'required|array|min:1',
|
||||
'component_ids.*' => 'exists:components,id',
|
||||
'is_ai_generated' => 'nullable|boolean',
|
||||
'ai_prompt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
// Проверяем: все компоненты — либо официальные, либо ваши
|
||||
$invalidComponents = Component::whereIn('id', $validated['component_ids'])
|
||||
->where(function ($query) {
|
||||
$query->where('is_official', false)
|
||||
->where('created_by_user_id', '!=', auth()->id());
|
||||
})
|
||||
->pluck('name', 'id')
|
||||
->toArray();
|
||||
|
||||
if (!empty($invalidComponents)) {
|
||||
return response()->json([
|
||||
'message' => 'Запрещено использовать неофициальные компоненты, созданные другими пользователями.',
|
||||
'invalid_components' => $invalidComponents
|
||||
], 403);
|
||||
}
|
||||
|
||||
// 👇 ВСТАВЛЯЕМ ПРОВЕРКУ СОВМЕСТИМОСТИ ЗДЕСЬ — ПЕРЕД СОЗДАНИЕМ СБОРКИ
|
||||
$validator = new BuildValidator();
|
||||
$compatibility = $validator->validateCompatibility($validated['component_ids']);
|
||||
|
||||
if (!$compatibility['valid']) {
|
||||
return response()->json([
|
||||
'message' => 'Сборка содержит несовместимые компоненты.',
|
||||
'errors' => $compatibility['errors'],
|
||||
'warnings' => $compatibility['warnings']
|
||||
], 422); // 422 Unprocessable Entity
|
||||
}
|
||||
|
||||
// ✅ Только если совместимость OK — создаём сборку
|
||||
$build = PCBuild::create([
|
||||
'user_id' => auth()->id(),
|
||||
'name' => $validated['name'],
|
||||
'description' => $validated['description'] ?? null,
|
||||
'is_ai_generated' => $validated['is_ai_generated'] ?? false,
|
||||
'ai_prompt' => $validated['ai_prompt'] ?? null,
|
||||
]);
|
||||
|
||||
$build->components()->attach($validated['component_ids']);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Сборка успешно создана.',
|
||||
'build' => $build->load('components'),
|
||||
'compatibility' => $compatibility // опционально — для отладки
|
||||
], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/builds/{id}",
|
||||
* summary="Получить одну сборку по ID",
|
||||
* tags={"PC Builds"},
|
||||
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
|
||||
* @OA\Response(response=200, description="Сборка найдена"),
|
||||
* @OA\Response(response=403, description="Запрещено: не ваша сборка"),
|
||||
* @OA\Response(response=404, description="Не найдено")
|
||||
* )
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$build = PCBuild::with('components')->findOrFail($id);
|
||||
|
||||
if ($build->user_id !== auth()->id()) {
|
||||
return response()->json([
|
||||
'message' => 'Вы не можете просматривать эту сборку.'
|
||||
], 403);
|
||||
}
|
||||
|
||||
return response()->json($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Put(
|
||||
* path="/api/builds/{id}",
|
||||
* summary="Обновить сборку",
|
||||
* tags={"PC Builds"},
|
||||
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
* @OA\JsonContent(
|
||||
* required={"name", "component_ids"},
|
||||
* @OA\Property(property="name", type="string"),
|
||||
* @OA\Property(property="description", type="string", nullable=true),
|
||||
* @OA\Property(property="component_ids", type="array", @OA\Items(type="integer")),
|
||||
* @OA\Property(property="is_ai_generated", type="boolean"),
|
||||
* @OA\Property(property="ai_prompt", type="string", nullable=true)
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(response=200, description="Сборка обновлена"),
|
||||
* @OA\Response(response=403, description="Запрещено")
|
||||
* )
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$build = PCBuild::findOrFail($id);
|
||||
|
||||
if ($build->user_id !== auth()->id()) {
|
||||
return response()->json([
|
||||
'message' => 'Вы не можете редактировать эту сборку.'
|
||||
], 403);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'component_ids' => 'required|array|min:1',
|
||||
'component_ids.*' => 'exists:components,id',
|
||||
'is_ai_generated' => 'nullable|boolean',
|
||||
'ai_prompt' => 'nullable|string',
|
||||
]);
|
||||
|
||||
// Проверка: все компоненты — либо официальные, либо ваши
|
||||
$invalidComponents = Component::whereIn('id', $validated['component_ids'])
|
||||
->where(function ($query) {
|
||||
$query->where('is_official', false)
|
||||
->where('created_by_user_id', '!=', auth()->id());
|
||||
})
|
||||
->pluck('name', 'id')
|
||||
->toArray();
|
||||
|
||||
if (!empty($invalidComponents)) {
|
||||
return response()->json([
|
||||
'message' => 'Запрещено использовать неофициальные компоненты, созданные другими пользователями.',
|
||||
'invalid_components' => $invalidComponents
|
||||
], 403);
|
||||
}
|
||||
|
||||
// 👇 ВСТАВЛЯЕМ ПРОВЕРКУ СОВМЕСТИМОСТИ ЗДЕСЬ — ПЕРЕД ОБНОВЛЕНИЕМ
|
||||
$validator = new BuildValidator();
|
||||
$compatibility = $validator->validateCompatibility($validated['component_ids']);
|
||||
|
||||
if (!$compatibility['valid']) {
|
||||
return response()->json([
|
||||
'message' => 'Сборка содержит несовместимые компоненты.',
|
||||
'errors' => $compatibility['errors'],
|
||||
'warnings' => $compatibility['warnings']
|
||||
], 422);
|
||||
}
|
||||
|
||||
// ✅ Обновляем сборку
|
||||
DB::transaction(function () use ($build, $validated) {
|
||||
$build->update([
|
||||
'name' => $validated['name'],
|
||||
'description' => $validated['description'] ?? null,
|
||||
'is_ai_generated' => $validated['is_ai_generated'] ?? $build->is_ai_generated,
|
||||
'ai_prompt' => $validated['ai_prompt'] ?? $build->ai_prompt,
|
||||
]);
|
||||
|
||||
$build->components()->sync($validated['component_ids']);
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Сборка обновлена.',
|
||||
'build' => $build->load('components'),
|
||||
'compatibility' => $compatibility // опционально
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Delete(
|
||||
* path="/api/builds/{id}",
|
||||
* summary="Удалить сборку",
|
||||
* tags={"PC Builds"},
|
||||
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
|
||||
* @OA\Response(response=200, description="Сборка удалена"),
|
||||
* @OA\Response(response=403, description="Запрещено")
|
||||
* )
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$build = PCBuild::findOrFail($id);
|
||||
|
||||
if ($build->user_id !== auth()->id()) {
|
||||
return response()->json([
|
||||
'message' => 'Вы не можете удалить эту сборку.'
|
||||
], 403);
|
||||
}
|
||||
|
||||
$build->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Сборка удалена.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,5 @@ class UsersController extends Controller
|
||||
return ['token' => $user->createToken('frontend')->plainTextToken];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user