'required|max:100|unique:users', 'email' => 'required|max:100|unique:users', 'password' => 'required|min:6|confirmed', 'type' => 'required|in:admin,user,creator,banned', 'email_verified_at' => 'nullable|date' ]; private const PAGINATED_COUNT = 20; /** * @OA\Get( * path="/api/users", * summary="Get list of users (paginated, only admin)", * tags={"Users"}, * security={{"bearerAuth": {}}}, * @OA\Response( * response=200, * description="List of users retrieved successfully", * @OA\JsonContent( * @OA\Property(property="data", type="array", * @OA\Items(ref="#/components/schemas/UserResource") * ), * @OA\Property(property="links", type="object"), * @OA\Property(property="meta", type="object") * ) * ), * @OA\Response( * response=403, * description="Forbidden — user is not authorized to view users" * ), * @OA\Response( * response=401, * description="Unauthenticated" * ) * ) */ public function index() { $this->authorize('viewAny', User::class); return UserResource::collection(User::paginate(self::PAGINATED_COUNT)); } /** * @OA\Post( * path="/api/users", * summary="Create a new user (only admin)", * tags={"Users"}, * security={{"bearerAuth": {}}}, * @OA\RequestBody( * required=true, * @OA\JsonContent( * required={"username","email","password","type"}, * @OA\Property(property="username", type="string", maxLength=100, example="newuser"), * @OA\Property(property="email", type="string", format="email", maxLength=100, example="newuser@example.com"), * @OA\Property(property="password", type="string", format="password", example="secret123"), * @OA\Property(property="type", type="string", enum={"admin","user"}, example="user") * ) * ), * @OA\Response( * response=201, * description="User created successfully", * @OA\JsonContent(ref="#/components/schemas/UserResource") * ), * @OA\Response( * response=422, * description="Validation error", * @OA\JsonContent( * @OA\Property(property="message", type="string", example="The given data was invalid."), * @OA\Property( * property="errors", * type="object", * example={ * "email": {"The email has already been taken."}, * "password": {"The password must be at least 6 characters."} * } * ) * ) * ), * @OA\Response( * response=403, * description="Forbidden — only admins can create users" * ), * @OA\Response( * response=401, * description="Unauthenticated" * ) * ) */ public function store(Request $request) { $this->authorize('create', User::class); $fields = $request->validate(self::FIELD_RULES); $fields['password'] = Hash::make($fields['password']); $user = User::create($fields); Log::writeLog("User '" . $user->username . "' is created by " . $request->user()->username); return new UserResource($user); } /** * @OA\Get( * path="/api/users/{id}", * summary="Get a specific user (only admin)", * tags={"Users"}, * security={{"bearerAuth": {}}}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="User ID", * @OA\Schema(type="integer", example=1) * ), * @OA\Response( * response=200, * description="User retrieved successfully", * @OA\JsonContent(ref="#/components/schemas/UserResource") * ), * @OA\Response( * response=404, * description="User not found" * ), * @OA\Response( * response=403, * description="Forbidden — user not authorized to view this resource" * ), * @OA\Response( * response=401, * description="Unauthenticated" * ) * ) */ public function show(User $user) { $this->authorize('view', $user); return new UserResource($user); } /** * @OA\Put( * path="/api/users/{id}", * summary="Update an existing user (only admin)", * tags={"Users"}, * security={{"bearerAuth": {}}}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="User ID", * @OA\Schema(type="integer", example=1) * ), * @OA\RequestBody( * required=true, * @OA\JsonContent( * required={"username","email","password","type"}, * @OA\Property(property="username", type="string", maxLength=100, example="updated_user"), * @OA\Property(property="email", type="string", format="email", maxLength=100, example="updated_user@example.com"), * @OA\Property(property="password", type="string", format="password", example="newpassword123"), * @OA\Property(property="type", type="string", enum={"admin","user"}, example="user") * ) * ), * @OA\Response( * response=200, * description="User updated successfully", * @OA\JsonContent(ref="#/components/schemas/UserResource") * ), * @OA\Response( * response=404, * description="User not found" * ), * @OA\Response( * response=422, * description="Validation error", * @OA\JsonContent( * @OA\Property(property="message", type="string", example="The given data was invalid."), * @OA\Property( * property="errors", * type="object", * example={ * "email": {"The email has already been taken."}, * "password": {"The password must be at least 6 characters."} * } * ) * ) * ), * @OA\Response( * response=403, * description="Forbidden — only admins can update users" * ), * @OA\Response( * response=401, * description="Unauthenticated" * ) * ) */ public function update(Request $request, User $user) { $this->authorize('update', $user); $fields = $request->validate(self::FIELD_RULES); if(!Hash::check($fields['password'], $user->password)) { $fields['password'] = Hash::make($fields['password']); } $user->update($fields); Log::writeLog("User '" . $user->username . "' is updated by " . $request->user()->username); return new UserResource($user); } /** * @OA\Delete( * path="/api/users/{id}", * summary="Delete a user (only admin)", * tags={"Users"}, * security={{"bearerAuth": {}}}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="User ID", * @OA\Schema(type="integer", example=1) * ), * @OA\Response( * response=204, * description="User deleted successfully (no content)" * ), * @OA\Response( * response=404, * description="User not found" * ), * @OA\Response( * response=403, * description="Forbidden — only admins can delete users" * ), * @OA\Response( * response=401, * description="Unauthenticated" * ) * ) */ public function destroy(Request $request, User $user) { $this->authorize('delete', $user); $user->delete(); Log::writeLog("User '" . $user->username . "' is deleted by " . $request->user()->username); } }