Logs, Categories created
This commit is contained in:
parent
823d498de7
commit
8ca7fa0fd0
@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Http\Resources\UserResource;
|
use App\Http\Resources\UserResource;
|
||||||
use App\Mail\EmailActivation;
|
use App\Mail\EmailActivation;
|
||||||
|
use App\Models\Log;
|
||||||
use App\Models\Token;
|
use App\Models\Token;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -59,6 +60,8 @@ class AuthController extends Controller
|
|||||||
|
|
||||||
$user = User::create($fields);
|
$user = User::create($fields);
|
||||||
|
|
||||||
|
Log::writeLog("User '" . $user->username . "' is registered");
|
||||||
|
|
||||||
$token = Token::existsToken($user, 'email_verification');
|
$token = Token::existsToken($user, 'email_verification');
|
||||||
if(!$token) {
|
if(!$token) {
|
||||||
$token = Token::createToken($user, 'email_verification');
|
$token = Token::createToken($user, 'email_verification');
|
||||||
@ -126,6 +129,8 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
$token = $user->createToken('auth_token')->plainTextToken;
|
$token = $user->createToken('auth_token')->plainTextToken;
|
||||||
|
|
||||||
|
Log::writeLog("User '" . $user->username . "' is logged into his account");
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'access_token' => $token,
|
'access_token' => $token,
|
||||||
'token_type' => 'Bearer',
|
'token_type' => 'Bearer',
|
||||||
@ -297,6 +302,8 @@ class AuthController extends Controller
|
|||||||
$user->password = $new_password;
|
$user->password = $new_password;
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
|
Log::writeLog("User '" . $user->username . "' is resetted his password");
|
||||||
|
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Your password was successfully changed!'
|
'message' => 'Your password was successfully changed!'
|
||||||
|
|||||||
@ -2,62 +2,185 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\StoreCategoryRequest;
|
use App\Http\Resources\CategoryResource;
|
||||||
use App\Http\Requests\UpdateCategoryRequest;
|
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
|
use App\Models\Log;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class CategoryController extends Controller
|
class CategoryController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* @OA\Get(
|
||||||
|
* path="/api/categories",
|
||||||
|
* summary="Get all categories",
|
||||||
|
* tags={"Categories"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="List of categories",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(ref="#/components/schemas/CategoryResource")
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return Category::all();
|
return CategoryResource::collection(Category::all());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a newly created resource in storage.
|
* @OA\Post(
|
||||||
|
* path="/api/categories",
|
||||||
|
* summary="Create a new category (only admin)",
|
||||||
|
* tags={"Categories"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\RequestBody(
|
||||||
|
* required=true,
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* required={"name"},
|
||||||
|
* @OA\Property(property="name", type="string", example="Physics")
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Category created successfully",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/CategoryResource")
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=403,
|
||||||
|
* description="Forbidden"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$this->authorize('create', Category::class);
|
||||||
$fields = $request->validate([
|
$fields = $request->validate([
|
||||||
'name' => 'required|max:150'
|
'name' => 'required|max:150'
|
||||||
]);
|
]);
|
||||||
$category = Category::create($fields);
|
$category = Category::create($fields);
|
||||||
|
|
||||||
return $category;
|
Log::writeLog("Category '" . $category->name . "' is created");
|
||||||
|
|
||||||
|
return new CategoryResource($category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* @OA\Get(
|
||||||
|
* path="/api/categories/{id}",
|
||||||
|
* summary="Get a specific category",
|
||||||
|
* tags={"Categories"},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* description="ID of the category",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Category retrieved successfully",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/CategoryResource")
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=404,
|
||||||
|
* description="Category not found"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
public function show(Category $category)
|
public function show(Category $category)
|
||||||
{
|
{
|
||||||
return $category;
|
return new CategoryResource($category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the specified resource in storage.
|
* @OA\Put(
|
||||||
|
* path="/api/categories/{id}",
|
||||||
|
* summary="Update a category (only admin)",
|
||||||
|
* tags={"Categories"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* description="ID of the category",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\RequestBody(
|
||||||
|
* required=true,
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* required={"name"},
|
||||||
|
* @OA\Property(property="name", type="string", example="Physics Updated")
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Category updated successfully",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/CategoryResource")
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=403,
|
||||||
|
* description="Forbidden"
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=404,
|
||||||
|
* description="Category not found"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, Category $category)
|
public function update(Request $request, Category $category)
|
||||||
{
|
{
|
||||||
|
$this->authorize('update', $category);
|
||||||
$fields = $request->validate([
|
$fields = $request->validate([
|
||||||
'name' => 'required|max:150'
|
'name' => 'required|max:150'
|
||||||
]);
|
]);
|
||||||
|
$old_category_name = $category->name;
|
||||||
$category->update($fields);
|
$category->update($fields);
|
||||||
|
|
||||||
return $category;
|
Log::writeLog("Category '$old_category_name' is renamed to '" . $category->name ."'");
|
||||||
|
|
||||||
|
return new CategoryResource($category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the specified resource from storage.
|
* @OA\Delete(
|
||||||
|
* path="/api/categories/{id}",
|
||||||
|
* summary="Delete a category (only admin)",
|
||||||
|
* tags={"Categories"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* description="ID of the category",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Category deleted successfully",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* @OA\Property(property="message", type="string", example="The category was deleted")
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=403,
|
||||||
|
* description="Forbidden"
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=404,
|
||||||
|
* description="Category not found"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
public function destroy(Category $category)
|
public function destroy(Category $category)
|
||||||
{
|
{
|
||||||
|
$this->authorize('delete', $category);
|
||||||
$category->delete();
|
$category->delete();
|
||||||
|
|
||||||
|
Log::writeLog("Category '" . $category->name . "' is deleted");
|
||||||
|
|
||||||
return ['message' => 'The category was deleted'];
|
return ['message' => 'The category was deleted'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\Info(
|
* @OA\Info(
|
||||||
* title="HoshiAI API",
|
* title="HoshiAI API",
|
||||||
@ -11,5 +15,5 @@ namespace App\Http\Controllers;
|
|||||||
*/
|
*/
|
||||||
abstract class Controller
|
abstract class Controller
|
||||||
{
|
{
|
||||||
//
|
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||||
}
|
}
|
||||||
|
|||||||
114
app/Http/Controllers/LogController.php
Normal file
114
app/Http/Controllers/LogController.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Resources\LogResource;
|
||||||
|
use App\Models\Log;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LogController extends Controller
|
||||||
|
{
|
||||||
|
private const PAGINATED_COUNT = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/logs",
|
||||||
|
* summary="Get all logs (paginated, only admin)",
|
||||||
|
* tags={"Logs"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="List of logs",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(ref="#/components/schemas/LogResource")
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=403,
|
||||||
|
* description="Forbidden"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$this->authorize('viewAny', Log::class);
|
||||||
|
return LogResource::collection(Log::paginate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/logs/{id}",
|
||||||
|
* summary="Get a specific log (only admin)",
|
||||||
|
* tags={"Logs"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* description="ID of the log",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Log retrieved successfully",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/LogResource")
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=403,
|
||||||
|
* description="Forbidden"
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=404,
|
||||||
|
* description="Log not found"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(Log $log)
|
||||||
|
{
|
||||||
|
$this->authorize('view', $log);
|
||||||
|
return $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Delete(
|
||||||
|
* path="/api/logs/{id}",
|
||||||
|
* summary="Delete a specific log (only admin)",
|
||||||
|
* tags={"Logs"},
|
||||||
|
* security={{"bearerAuth": {}}},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* description="ID of the log",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Log deleted successfully",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* @OA\Property(property="message", type="string", example="This log is successfully deleted")
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=403,
|
||||||
|
* description="Forbidden"
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=404,
|
||||||
|
* description="Log not found"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(Log $log)
|
||||||
|
{
|
||||||
|
$this->authorize('delete', $log);
|
||||||
|
|
||||||
|
$log->delete();
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'This log is successfully deleted'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
app/Http/Resources/CategoryResource.php
Normal file
54
app/Http/Resources/CategoryResource.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="CategoryResource",
|
||||||
|
* type="object",
|
||||||
|
* title="Category",
|
||||||
|
* description="Category resource with dynamic count",
|
||||||
|
* @OA\Property(
|
||||||
|
* property="id",
|
||||||
|
* type="integer",
|
||||||
|
* example=1
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="name",
|
||||||
|
* type="string",
|
||||||
|
* example="Books"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="created_at",
|
||||||
|
* type="string",
|
||||||
|
* format="date-time",
|
||||||
|
* example="2025-11-10T18:00:00Z"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="count",
|
||||||
|
* type="integer",
|
||||||
|
* example=5,
|
||||||
|
* description="Dynamic count of related items"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class CategoryResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'name' => $this->name,
|
||||||
|
'created_at' => $this->created_at,
|
||||||
|
'count' => $this->count ?? 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/Http/Resources/LogResource.php
Normal file
47
app/Http/Resources/LogResource.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="LogResource",
|
||||||
|
* type="object",
|
||||||
|
* title="Log",
|
||||||
|
* description="Log resource",
|
||||||
|
* @OA\Property(
|
||||||
|
* property="id",
|
||||||
|
* type="integer",
|
||||||
|
* example=1
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="description",
|
||||||
|
* type="string",
|
||||||
|
* example="User logged in"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="created_at",
|
||||||
|
* type="string",
|
||||||
|
* format="date-time",
|
||||||
|
* example="2025-11-10T17:45:00.000000Z"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class LogResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'description' => $this->description,
|
||||||
|
'created_at' => $this->created_at
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Models/Log.php
Normal file
40
app/Models/Log.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Log extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'description',
|
||||||
|
'type'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creating new log
|
||||||
|
* @param string $descpr
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function writeLog(string $descpr, string $type = 'access')
|
||||||
|
{
|
||||||
|
self::create(['description' => $descpr, 'type' => $type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'created_at' => 'datetime'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,22 +8,6 @@ use Illuminate\Auth\Access\Response;
|
|||||||
|
|
||||||
class CategoryPolicy
|
class CategoryPolicy
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*/
|
|
||||||
public function viewAny(User $user): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*/
|
|
||||||
public function view(User $user, Category $category): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the user can create models.
|
* Determine whether the user can create models.
|
||||||
*/
|
*/
|
||||||
@ -47,20 +31,4 @@ class CategoryPolicy
|
|||||||
{
|
{
|
||||||
return $user->type === 'admin';
|
return $user->type === 'admin';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can restore the model.
|
|
||||||
*/
|
|
||||||
public function restore(User $user, Category $category): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can permanently delete the model.
|
|
||||||
*/
|
|
||||||
public function forceDelete(User $user, Category $category): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
34
app/Policies/LogPolicy.php
Normal file
34
app/Policies/LogPolicy.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Log;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Access\Response;
|
||||||
|
|
||||||
|
class LogPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->type === 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Log $log): bool
|
||||||
|
{
|
||||||
|
return $user->type === 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Log $log): bool
|
||||||
|
{
|
||||||
|
return $user->type === 'admin';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -40,6 +40,11 @@ return [
|
|||||||
'driver' => 'session',
|
'driver' => 'session',
|
||||||
'provider' => 'users',
|
'provider' => 'users',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'sanctum' => [
|
||||||
|
'driver' => 'sanctum',
|
||||||
|
'provider' => 'users',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
29
database/migrations/2025_11_10_200607_create_logs_table.php
Normal file
29
database/migrations/2025_11_10_200607_create_logs_table.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('logs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string("description", 255);
|
||||||
|
$table->enum('type', ['error', 'access'])->default('access');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('logs');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -2,14 +2,24 @@
|
|||||||
|
|
||||||
use App\Http\Controllers\AuthController;
|
use App\Http\Controllers\AuthController;
|
||||||
use App\Http\Controllers\CategoryController;
|
use App\Http\Controllers\CategoryController;
|
||||||
|
use App\Http\Controllers\LogController;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
// Route::get('/user', function (Request $request) {
|
|
||||||
// return $request->user();
|
|
||||||
// })->middleware('auth:sanctum');
|
|
||||||
|
|
||||||
Route::apiResource('categories', CategoryController::class);
|
|
||||||
|
// CategoryController
|
||||||
|
Route::get('categories', [CategoryController::class, 'index']);
|
||||||
|
Route::get('categories/{category}', [CategoryController::class, 'show']);
|
||||||
|
|
||||||
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
Route::post('categories', [CategoryController::class, 'store']);
|
||||||
|
Route::put('categories/{category}', [CategoryController::class, 'update']);
|
||||||
|
Route::delete('categories/{category}', [CategoryController::class, 'destroy']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::apiResource('logs', LogController::class)
|
||||||
|
->only(['index', 'show', 'destroy'])->middleware('auth:sanctum');
|
||||||
|
|
||||||
// AuthController
|
// AuthController
|
||||||
Route::post('/auth/register', [ AuthController::class, 'register' ]);
|
Route::post('/auth/register', [ AuthController::class, 'register' ]);
|
||||||
@ -18,4 +28,8 @@ Route::post('/auth/logout', [ AuthController::class, 'logout' ])->middleware('au
|
|||||||
Route::post('/auth/forgot-password', [ AuthController::class, 'forgotPassword' ]);
|
Route::post('/auth/forgot-password', [ AuthController::class, 'forgotPassword' ]);
|
||||||
Route::post('/auth/reset-password', [ AuthController::class, 'resetPassword' ]);
|
Route::post('/auth/reset-password', [ AuthController::class, 'resetPassword' ]);
|
||||||
Route::post('/auth/activate-account', [ AuthController::class, 'confirmationAccount' ]);
|
Route::post('/auth/activate-account', [ AuthController::class, 'confirmationAccount' ]);
|
||||||
|
|
||||||
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
Route::post('/auth/logout', [ AuthController::class, 'logout' ]);
|
||||||
Route::get('/auth/me', [ AuthController::class, 'me' ])->middleware('auth:sanctum');
|
Route::get('/auth/me', [ AuthController::class, 'me' ])->middleware('auth:sanctum');
|
||||||
|
});
|
||||||
@ -546,10 +546,399 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/api/categories": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Categories"
|
||||||
|
],
|
||||||
|
"summary": "Get all categories",
|
||||||
|
"operationId": "3f5817a34833d0a1f4af4548dd3aeaba",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of categories",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/CategoryResource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Categories"
|
||||||
|
],
|
||||||
|
"summary": "Create a new category (only admin)",
|
||||||
|
"operationId": "71fcad552bb0eaba9fb191fd8d8dcab0",
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Physics"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Category created successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/CategoryResource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/categories/{id}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Categories"
|
||||||
|
],
|
||||||
|
"summary": "Get a specific category",
|
||||||
|
"operationId": "c68e76d323c008827a9e47398b1583de",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of the category",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Category retrieved successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/CategoryResource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Category not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"Categories"
|
||||||
|
],
|
||||||
|
"summary": "Update a category (only admin)",
|
||||||
|
"operationId": "0e686b2748211cc688333ed705dc111f",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of the category",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Physics Updated"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Category updated successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/CategoryResource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Category not found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Categories"
|
||||||
|
],
|
||||||
|
"summary": "Delete a category (only admin)",
|
||||||
|
"operationId": "4c12e22a7f8c617bd83bfa1fdc05428d",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of the category",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Category deleted successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "The category was deleted"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Category not found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/logs": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Logs"
|
||||||
|
],
|
||||||
|
"summary": "Get all logs (paginated, only admin)",
|
||||||
|
"operationId": "07258c00ce1b2cbc7c7151a7cc8ca986",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of logs",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/LogResource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/logs/{id}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Logs"
|
||||||
|
],
|
||||||
|
"summary": "Get a specific log (only admin)",
|
||||||
|
"operationId": "caa09131dde473dca25ea025d181146a",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of the log",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Log retrieved successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/LogResource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Log not found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"Logs"
|
||||||
|
],
|
||||||
|
"summary": "Delete a specific log (only admin)",
|
||||||
|
"operationId": "2a0e57b9168eaca7e207f5b35f469666",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of the log",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Log deleted successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "This log is successfully deleted"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Log not found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"schemas": {
|
"schemas": {
|
||||||
|
"CategoryResource": {
|
||||||
|
"title": "Category",
|
||||||
|
"description": "Category resource with dynamic count",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Books"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"example": "2025-11-10T18:00:00Z"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"description": "Dynamic count of related items",
|
||||||
|
"type": "integer",
|
||||||
|
"example": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"LogResource": {
|
||||||
|
"title": "Log",
|
||||||
|
"description": "Log resource",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "User logged in"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"example": "2025-11-10T17:45:00.000000Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"UserResource": {
|
"UserResource": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
@ -596,6 +985,14 @@
|
|||||||
{
|
{
|
||||||
"name": "Auth",
|
"name": "Auth",
|
||||||
"description": "Auth"
|
"description": "Auth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Categories",
|
||||||
|
"description": "Categories"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Logs",
|
||||||
|
"description": "Logs"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user