coursework tasks 1 to 10
This commit is contained in:
169
app/Http/Controllers/AvailabilitiesController.php
Normal file
169
app/Http/Controllers/AvailabilitiesController.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\EmployeeAvailability;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AvailabilitiesController extends Controller
|
||||
{
|
||||
// GET api/admin/availabilities?employee_id=5&date=2025-06-15
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = EmployeeAvailability::query();
|
||||
|
||||
if ($request->employee_id) {
|
||||
$query->where('employee_id', $request->employee_id);
|
||||
}
|
||||
if ($request->date) {
|
||||
$query->where('date', $request->date);
|
||||
}
|
||||
|
||||
$availabilities = $query->get();
|
||||
return response()->json($availabilities);
|
||||
}
|
||||
|
||||
// POST api/admin/availabilities - создать один слот
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'starttime' => 'required',
|
||||
'endtime' => 'required|after:starttime',
|
||||
'isavailable' => 'boolean'
|
||||
]);
|
||||
|
||||
$availability = EmployeeAvailability::create($request->all());
|
||||
return response()->json($availability, 201);
|
||||
}
|
||||
|
||||
// POST api/admin/availabilities/bulk - создать несколько слотов
|
||||
public function bulkStore(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'intervals' => 'required|array|min:1'
|
||||
]);
|
||||
|
||||
$availabilities = [];
|
||||
foreach ($request->intervals as $interval) {
|
||||
$availability = EmployeeAvailability::create([
|
||||
'employee_id' => $request->employee_id,
|
||||
'date' => $request->date,
|
||||
'starttime' => $interval['start'],
|
||||
'endtime' => $interval['end'],
|
||||
'isavailable' => true
|
||||
]);
|
||||
$availabilities[] = $availability;
|
||||
}
|
||||
|
||||
return response()->json($availabilities, 201);
|
||||
}
|
||||
|
||||
// DELETE api/admin/availabilities/{id} - удалить слот (брони остаются!)
|
||||
public function destroy($id)
|
||||
{
|
||||
$availability = EmployeeAvailability::findOrFail($id);
|
||||
$availability->delete();
|
||||
|
||||
return response()->json(['message' => 'Слот удален из расписания (брони сохранены)']);
|
||||
}
|
||||
public function publicAvailability(Request $request)
|
||||
{
|
||||
$serviceId = $request->query('service_id');
|
||||
$date = $request->query('date');
|
||||
|
||||
if (!$serviceId || !$date) {
|
||||
return response()->json(['error' => 'service_id и date обязательны'], 400);
|
||||
}
|
||||
|
||||
// Найти услугу и получить длительность
|
||||
$service = \App\Models\Services::find($serviceId);
|
||||
if (!$service) {
|
||||
return response()->json(['error' => 'Услуга не найдена'], 404);
|
||||
}
|
||||
|
||||
$durationMinutes = $service->durationminutes;
|
||||
|
||||
// Найти сотрудников с расписанием на эту дату
|
||||
$availabilities = \App\Models\EmployeeAvailability::where('date', $date)
|
||||
->where('isavailable', true)
|
||||
->with('employee') // связь с User
|
||||
->get();
|
||||
|
||||
$freeSlots = [];
|
||||
|
||||
foreach ($availabilities as $availability) {
|
||||
$employeeId = $availability->employee_id;
|
||||
|
||||
// Найти занятые слоты этого сотрудника
|
||||
$bookings = \App\Models\Booking::where('employee_id', $employeeId)
|
||||
->where('bookingdate', $date)
|
||||
->where('status', '!=', 'cancelled')
|
||||
->pluck('starttime', 'endtime');
|
||||
|
||||
// Генерировать возможные слоты с учетом duration
|
||||
$start = new \DateTime($availability->starttime);
|
||||
$end = new \DateTime($availability->endtime);
|
||||
|
||||
$current = clone $start;
|
||||
while ($current < $end) {
|
||||
$slotEnd = clone $current;
|
||||
$slotEnd->modify("+{$durationMinutes} minutes");
|
||||
|
||||
// Проверить пересечение с бронями
|
||||
$isFree = true;
|
||||
foreach ($bookings as $bookingStart => $bookingEnd) {
|
||||
$bookingStartTime = new \DateTime($bookingStart);
|
||||
$bookingEndTime = new \DateTime($bookingEnd);
|
||||
|
||||
if ($current < $bookingEndTime && $slotEnd > $bookingStartTime) {
|
||||
$isFree = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isFree && $slotEnd <= $end) {
|
||||
$freeSlots[] = [
|
||||
'employee_id' => $employeeId,
|
||||
'start' => $current->format('H:i'),
|
||||
'end' => $slotEnd->format('H:i')
|
||||
];
|
||||
}
|
||||
|
||||
$current->modify('+30 minutes'); // шаг 30 мин
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json($freeSlots);
|
||||
}
|
||||
public function cancel(Request $request, $id)
|
||||
{
|
||||
$booking = Booking::findOrFail($id);
|
||||
|
||||
// Проверка: только автор брони может отменить
|
||||
if ($booking->client_id != auth()->id()) {
|
||||
return response()->json(['error' => 'Можете отменить только свою бронь'], 403);
|
||||
}
|
||||
|
||||
// Проверка: нельзя отменить уже отмененную/выполненную
|
||||
if ($booking->status != 'confirmed') {
|
||||
return response()->json(['error' => 'Можно отменить только подтвержденные брони'], 400);
|
||||
}
|
||||
|
||||
// Обновить статус
|
||||
$booking->update([
|
||||
'status' => 'cancelled',
|
||||
'cancelledby' => 'client',
|
||||
'cancelreason' => $request->reason ?? null
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Бронь отменена',
|
||||
'booking' => $booking
|
||||
]);
|
||||
}
|
||||
}
|
||||
108
app/Http/Controllers/BookingsController.php
Normal file
108
app/Http/Controllers/BookingsController.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Booking;
|
||||
use App\Models\Services;
|
||||
use App\Models\EmployeeAvailability;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class BookingsController extends Controller
|
||||
{
|
||||
// POST api/bookings - создание брони (ТОЛЬКО клиенты)
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'service_id' => 'required|exists:services,id',
|
||||
'employee_id' => 'required|exists:users,id',
|
||||
'date' => 'required|date',
|
||||
'starttime' => 'required'
|
||||
]);
|
||||
|
||||
$clientId = auth()->id();
|
||||
if (!$clientId) {
|
||||
return response()->json(['error' => 'Авторизация обязательна'], 401);
|
||||
}
|
||||
|
||||
// Проверить активную услугу
|
||||
$service = Services::where('id', $request->service_id)
|
||||
->where('isactive', true)
|
||||
->first();
|
||||
if (!$service) {
|
||||
return response()->json(['error' => 'Услуга неактивна или не найдена'], 400);
|
||||
}
|
||||
|
||||
$durationMinutes = $service->durationminutes;
|
||||
$endtime = date('H:i:s', strtotime($request->starttime . " +{$durationMinutes} minutes"));
|
||||
|
||||
// Проверить доступность сотрудника
|
||||
$availability = EmployeeAvailability::where('employee_id', $request->employee_id)
|
||||
->where('date', $request->date)
|
||||
->where('starttime', '<=', $request->starttime)
|
||||
->where('endtime', '>=', $endtime)
|
||||
->where('isavailable', true)
|
||||
->first();
|
||||
|
||||
if (!$availability) {
|
||||
return response()->json(['error' => 'Сотрудник недоступен в это время'], 400);
|
||||
}
|
||||
|
||||
// Проверить уникальность слота
|
||||
$bookingExists = Booking::where('employee_id', $request->employee_id)
|
||||
->where('bookingdate', $request->date)
|
||||
->where('starttime', $request->starttime)
|
||||
->whereIn('status', ['confirmed', 'completed'])
|
||||
->exists();
|
||||
|
||||
if ($bookingExists) {
|
||||
return response()->json(['error' => 'Слот уже забронирован'], 400);
|
||||
}
|
||||
|
||||
// Создать бронь
|
||||
$bookingNumber = 'CL-' . date('Y') . '-' . str_pad(Booking::count() + 1, 4, '0', STR_PAD_LEFT);
|
||||
|
||||
$booking = Booking::create([
|
||||
'bookingnumber' => $bookingNumber,
|
||||
'client_id' => $clientId,
|
||||
'employee_id' => $request->employee_id,
|
||||
'service_id' => $request->service_id,
|
||||
'bookingdate' => $request->date,
|
||||
'starttime' => $request->starttime,
|
||||
'endtime' => $endtime,
|
||||
'status' => 'confirmed'
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'booking' => $booking,
|
||||
'message' => 'Бронирование создано №' . $bookingNumber
|
||||
], 201);
|
||||
}
|
||||
|
||||
// POST api/bookings/{id}/cancel - отмена клиентом
|
||||
public function cancel(Request $request, $id)
|
||||
{
|
||||
$booking = Booking::findOrFail($id);
|
||||
|
||||
// Только автор брони может отменить
|
||||
if ($booking->client_id != auth()->id()) {
|
||||
return response()->json(['error' => 'Можете отменить только свою бронь'], 403);
|
||||
}
|
||||
|
||||
// Только confirmed брони
|
||||
if ($booking->status != 'confirmed') {
|
||||
return response()->json(['error' => 'Можно отменить только подтвержденные'], 400);
|
||||
}
|
||||
|
||||
$booking->update([
|
||||
'status' => 'cancelled',
|
||||
'cancelledby' => 'client',
|
||||
'cancelreason' => $request->reason ?? null
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Бронь отменена',
|
||||
'booking' => $booking
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,78 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Services;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServicesController extends Controller
|
||||
{
|
||||
//
|
||||
// GET api/admin/services - список активных услуг
|
||||
public function index()
|
||||
{
|
||||
$services = Services::where('isactive', true)->get();
|
||||
return response()->json($services);
|
||||
}
|
||||
|
||||
// POST api/admin/services - создать услугу
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'required|string',
|
||||
'durationminutes' => 'required|integer|min:1|max:500',
|
||||
'price' => 'required|numeric|min:0'
|
||||
]);
|
||||
|
||||
$service = Services::create([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'durationminutes' => $request->durationminutes,
|
||||
'price' => $request->price,
|
||||
'isactive' => true // по умолчанию активна
|
||||
]);
|
||||
|
||||
return response()->json($service, 201);
|
||||
}
|
||||
|
||||
// PUT api/admin/services/{id} - обновить услугу
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$service = Services::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'required|string',
|
||||
'durationminutes' => 'required|integer|min:1|max:500',
|
||||
'price' => 'required|numeric|min:0'
|
||||
]);
|
||||
|
||||
$service->update([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'durationminutes' => $request->durationminutes,
|
||||
'price' => $request->price,
|
||||
]);
|
||||
|
||||
return response()->json($service);
|
||||
}
|
||||
|
||||
// DELETE api/admin/services/{id} - только если нет активных броней
|
||||
public function destroy($id)
|
||||
{
|
||||
$service = Services::findOrFail($id);
|
||||
|
||||
// ПРОВЕРКА: нельзя удалить услугу с активными бронями
|
||||
$activeBookings = \App\Models\Booking::where('service_id', $id)
|
||||
->where('status', '!=', 'cancelled')
|
||||
->exists();
|
||||
|
||||
if ($activeBookings) {
|
||||
return response()->json([
|
||||
'error' => 'Нельзя удалить услугу с активными бронями'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$service->delete();
|
||||
return response()->json(['message' => 'Услуга удалена']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,32 +5,30 @@ namespace App\Http\Controllers;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use SebastianBergmann\CodeCoverage\Report\Xml\Project;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function create(Request $request)
|
||||
{
|
||||
$user = new User();
|
||||
$name = $request->get(key:'name');
|
||||
$password = Hash::make($request->get(key:'password'));
|
||||
$email = $request->get(key: 'email');
|
||||
// /api/register - ТОЛЬКО клиенты (role = client)
|
||||
public function register(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email|unique:users',
|
||||
'password' => 'required|min:6'
|
||||
]);
|
||||
|
||||
$user->name = $name;
|
||||
$user->email = $email;
|
||||
$user->password = $password;
|
||||
$user->save();
|
||||
$user = User::create([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
'role' => 'client' // ТОЛЬКО клиенты
|
||||
]);
|
||||
|
||||
dispatch(function() use ($user) {
|
||||
$project= new Project();
|
||||
$project->title = 'default project';
|
||||
$project->description = 'test';
|
||||
$project->creator_user_id = $user->id;
|
||||
$project->save();
|
||||
|
||||
});
|
||||
|
||||
return ['toker' => $user->createToken('frotend')];
|
||||
|
||||
}
|
||||
$token = $user->createToken('client-token')->plainTextToken;
|
||||
|
||||
return response()->json([
|
||||
'user' => $user,
|
||||
'token' => $token
|
||||
], 201);
|
||||
}
|
||||
}
|
||||
|
||||
16
app/Http/Middleware/CheckRole.php
Normal file
16
app/Http/Middleware/CheckRole.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace App\Http\Middleware;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CheckRole
|
||||
{
|
||||
public function handle(Request $request, Closure $next, $role)
|
||||
{
|
||||
if (!auth()->check() || !auth()->user()->isEmployeeOrAdmin()) {
|
||||
return response()->json(['error' => 'Доступ запрещен'], 403);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
23
app/Models/Booking.php
Normal file
23
app/Models/Booking.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// бронирование ĸлиентов
|
||||
class Booking extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'bookings';
|
||||
|
||||
protected $fillable = [
|
||||
'bookingnumber',
|
||||
'client_id',
|
||||
'employee_id',
|
||||
'service_id',
|
||||
'bookingdate',
|
||||
'starttime',
|
||||
'endtime',
|
||||
'status',
|
||||
'cancelledby',
|
||||
'cancelreason'
|
||||
];
|
||||
}
|
||||
10
app/Models/EmployeeAvailability.php
Normal file
10
app/Models/EmployeeAvailability.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// расписание сотрудниĸов
|
||||
class EmployeeAvailability extends Model {
|
||||
use HasFactory;
|
||||
protected $table = 'employee_availabilities';
|
||||
protected $fillable = ['employee_id','date','starttime','endtime','isavailable'];
|
||||
}
|
||||
@@ -2,9 +2,24 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Services extends Model
|
||||
class Services extends Model // услуги ĸлининга
|
||||
{
|
||||
//
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'durationminutes',
|
||||
'price',
|
||||
'isactive',
|
||||
];
|
||||
|
||||
// Простая связь с bookings, если нужно
|
||||
public function bookings()
|
||||
{
|
||||
return $this->hasMany(Booking::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,43 +2,27 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
class User extends Authenticatable
|
||||
class User extends Authenticatable // все пользователи системы
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasApiTokens, HasFactory, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
'role',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
@@ -46,4 +30,16 @@ class User extends Authenticatable
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
// Проверяет админ или сотрудник
|
||||
public function isEmployeeOrAdmin()
|
||||
{
|
||||
return $this->role == 'employee' || $this->role == 'admin';
|
||||
}
|
||||
|
||||
// Для запросов - все сотрудники и админы
|
||||
public static function scopeEmployeeOrAdmin($query)
|
||||
{
|
||||
return $query->whereIn('role', ['employee', 'admin']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
//
|
||||
})
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->alias([
|
||||
'role:employee' => \App\Http\Middleware\CheckRole::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
})->create();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up() {
|
||||
Schema::create('employee_availabilities', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('employee_id');
|
||||
$table->date('date');
|
||||
$table->time('starttime');
|
||||
$table->time('endtime');
|
||||
$table->boolean('isavailable')->default(true);
|
||||
$table->timestamps(); // автоматическое создание created_at и updated_at
|
||||
|
||||
$table->foreign('employee_id')->references('id')->on('users');
|
||||
});
|
||||
}
|
||||
|
||||
public function down() {
|
||||
Schema::dropIfExists('employee_availabilities');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up() {
|
||||
Schema::create('bookings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('bookingnumber');
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->unsignedBigInteger('employee_id');
|
||||
$table->unsignedBigInteger('service_id');
|
||||
$table->date('bookingdate');
|
||||
$table->time('starttime');
|
||||
$table->time('endtime');
|
||||
$table->enum('status', ['confirmed', 'cancelled', 'completed'])->default('confirmed');
|
||||
$table->enum('cancelledby', ['client', 'admin'])->nullable();
|
||||
$table->text('cancelreason')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
// Внешние ключи
|
||||
$table->foreign('client_id')->references('id')->on('users');
|
||||
$table->foreign('employee_id')->references('id')->on('users');
|
||||
$table->foreign('service_id')->references('id')->on('services');
|
||||
|
||||
// УНИКАЛЬНЫЙ ИНДЕКС
|
||||
$table->unique(['employee_id', 'bookingdate', 'starttime'], 'unique_booking_slot');
|
||||
});
|
||||
}
|
||||
|
||||
public function down() {
|
||||
Schema::dropIfExists('bookings');
|
||||
}
|
||||
};
|
||||
@@ -1,16 +1,45 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\ServicesController;
|
||||
use App\Http\Controllers\BookingsController;
|
||||
use App\Http\Controllers\AvailabilitiesController;
|
||||
use App\Http\Controllers\CategoriesController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\CategoriesController;
|
||||
|
||||
|
||||
Route::get('/user', function (Request $request) {
|
||||
return $request->user();
|
||||
})->middleware('auth:sanctum');
|
||||
|
||||
// РЕГИСТРАЦИЯ ТОЛЬКО КЛИЕНТОВ (публичный)
|
||||
Route::post('/register', [UserController::class, 'register']);
|
||||
|
||||
// Существующие роуты categories
|
||||
Route::get('/categories', [CategoriesController::class, 'index'])->middleware('auth:sanctum');
|
||||
Route::get('/categories/{id}', [CategoriesController::class, 'show']);
|
||||
Route::post( '/categories', [CategoriesController::class, 'create']);
|
||||
Route::post( '/users', [UserController::class, 'create']);
|
||||
Route::post('/categories', [CategoriesController::class, 'create']);
|
||||
|
||||
// ПУБЛИЧНЫЙ API доступности (без авторизации)
|
||||
Route::get('/availability', [AvailabilitiesController::class, 'publicAvailability']);
|
||||
|
||||
// КЛИЕНТСКИЕ РОУТЫ БРОНИРОВАНИЙ (auth:sanctum)
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
Route::post('/bookings', [BookingsController::class, 'store']); // Пункт 9
|
||||
Route::post('/bookings/{id}/cancel', [BookingsController::class, 'cancel']); // Пункт 10
|
||||
});
|
||||
|
||||
// АДМИН РОУТЫ - ТОЛЬКО employee/admin (role:employee)
|
||||
Route::middleware(['auth:sanctum', 'role:employee'])->prefix('admin')->group(function () {
|
||||
// CRUD услуги
|
||||
Route::get('/services', [ServicesController::class, 'index']);
|
||||
Route::post('/services', [ServicesController::class, 'store']);
|
||||
Route::put('/services/{id}', [ServicesController::class, 'update']);
|
||||
Route::delete('/services/{id}', [ServicesController::class, 'destroy']);
|
||||
|
||||
// CRUD расписание
|
||||
Route::get('/availabilities', [AvailabilitiesController::class, 'index']);
|
||||
Route::post('/availabilities', [AvailabilitiesController::class, 'store']);
|
||||
Route::post('/availabilities/bulk', [AvailabilitiesController::class, 'bulkStore']);
|
||||
Route::delete('/availabilities/{id}', [AvailabilitiesController::class, 'destroy']);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user