update controllers logic
This commit is contained in:
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Administrator;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Teachers\TeacherAssignmentDeleteRequest;
|
||||
use App\Http\Requests\Teachers\TeacherAssignmentListRequest;
|
||||
use App\Http\Requests\Teachers\TeacherAssignmentStoreRequest;
|
||||
@@ -32,8 +32,13 @@ class TeacherClassAssignmentController extends BaseApiController
|
||||
|
||||
public function store(TeacherAssignmentStoreRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$payload['updated_by'] = (int) (auth()->id() ?? 0);
|
||||
$payload['updated_by'] = $userId;
|
||||
|
||||
$result = $this->assignmentService->assign($payload);
|
||||
$status = $result['ok'] ? 200 : 422;
|
||||
@@ -55,4 +60,17 @@ class TeacherClassAssignmentController extends BaseApiController
|
||||
'message' => $result['message'] ?? '',
|
||||
], $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,9 +46,14 @@ class AssignmentApiController extends Controller
|
||||
], 422);
|
||||
}
|
||||
|
||||
$userId = (int) ($request->user()?->id ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
$assignment = $this->assignmentService->storeAssignment(
|
||||
data: $validator->validated(),
|
||||
updatedBy: $request->user()?->id
|
||||
updatedBy: $userId
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
|
||||
@@ -31,9 +31,14 @@ class AdminAttendanceApiController extends Controller
|
||||
|
||||
public function updateManagement(UpdateAttendanceManagementRequest $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user === null) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
try {
|
||||
return response()->json(
|
||||
$this->attendanceService->updateAttendanceManagement(auth()->user(), $request->validated())
|
||||
$this->attendanceService->updateAttendanceManagement($user, $request->validated())
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
@@ -42,9 +47,14 @@ class AdminAttendanceApiController extends Controller
|
||||
|
||||
public function addEntry(AdminAddAttendanceEntryRequest $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user === null) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
try {
|
||||
return response()->json(
|
||||
$this->attendanceService->adminAddEntry(auth()->user(), $request->validated())
|
||||
$this->attendanceService->adminAddEntry($user, $request->validated())
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\Api\Attendance;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\ApplicationUrlService;
|
||||
use App\Services\AttendanceCommentTemplateService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -11,10 +12,22 @@ use Illuminate\Support\Facades\Validator;
|
||||
class AttendanceCommentTemplateController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected AttendanceCommentTemplateService $service
|
||||
protected AttendanceCommentTemplateService $service,
|
||||
protected ApplicationUrlService $urls,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap URLs for admin UIs (legacy CodeIgniter parity + SPA).
|
||||
*/
|
||||
public function bootstrapUrls(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $this->urls->attendanceCommentTemplateBootstrapData(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$activeOnly = filter_var(
|
||||
@@ -119,4 +132,83 @@ class AttendanceCommentTemplateController extends Controller
|
||||
'message' => 'Template deleted successfully.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CodeIgniter {@see \App\Controllers\View\AttendanceCommentTemplateController::save}
|
||||
* POST fields: id?, min_score, max_score, template_text, is_active (checkbox "on").
|
||||
*/
|
||||
public function legacySave(Request $request): JsonResponse
|
||||
{
|
||||
$id = $request->input('id');
|
||||
$hasId = $id !== null && $id !== '' && (int) $id > 0;
|
||||
|
||||
$rules = [
|
||||
'min_score' => ['required', 'integer', 'min:0', 'max:100'],
|
||||
'max_score' => ['required', 'integer', 'min:0', 'max:100'],
|
||||
'template_text' => ['required', 'string', 'max:5000'],
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
|
||||
$validator->after(function ($v) use ($request) {
|
||||
$min = (int) $request->input('min_score');
|
||||
$max = (int) $request->input('max_score');
|
||||
if ($max < $min) {
|
||||
$v->errors()->add('max_score', 'The max_score field must be greater than or equal to min_score.');
|
||||
}
|
||||
});
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$isActive = $this->legacyIsActive($request);
|
||||
|
||||
$payload = [
|
||||
'min_score' => (int) $request->input('min_score'),
|
||||
'max_score' => (int) $request->input('max_score'),
|
||||
'template_text' => (string) $request->input('template_text'),
|
||||
'is_active' => $isActive,
|
||||
];
|
||||
|
||||
if ($hasId) {
|
||||
$this->service->update((int) $id, $payload);
|
||||
} else {
|
||||
$this->service->create($payload);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* CodeIgniter {@see \App\Controllers\View\AttendanceCommentTemplateController::delete}.
|
||||
*/
|
||||
public function legacyDelete(Request $request): JsonResponse
|
||||
{
|
||||
$id = $request->input('id');
|
||||
if ($id === null || $id === '' || (int) $id <= 0) {
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => 'ID not provided',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$this->service->delete((int) $id);
|
||||
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
|
||||
private function legacyIsActive(Request $request): bool
|
||||
{
|
||||
$raw = $request->input('is_active');
|
||||
|
||||
return $raw === 'on'
|
||||
|| $raw === 1
|
||||
|| $raw === '1'
|
||||
|| $raw === true
|
||||
|| $raw === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Attendance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Attendance\LateSlipLogIndexRequest;
|
||||
use App\Http\Resources\Attendance\LateSlipLogCollection;
|
||||
use App\Http\Resources\Attendance\LateSlipLogResource;
|
||||
|
||||
@@ -42,9 +42,14 @@ class StaffAttendanceApiController extends Controller
|
||||
|
||||
public function saveAdmins(SaveAdminAttendanceRequest $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user === null) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
try {
|
||||
return response()->json(
|
||||
$this->staffAttendanceService->saveAdmins(auth()->user(), $request->validated())
|
||||
$this->staffAttendanceService->saveAdmins($user, $request->validated())
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
@@ -53,9 +58,14 @@ class StaffAttendanceApiController extends Controller
|
||||
|
||||
public function saveCell(SaveStaffAttendanceCellRequest $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user === null) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
try {
|
||||
return response()->json(
|
||||
$this->staffAttendanceService->saveCell(auth()->user(), $request->validated())
|
||||
$this->staffAttendanceService->saveCell($user, $request->validated())
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
|
||||
@@ -33,10 +33,15 @@ class TeacherAttendanceApiController extends Controller
|
||||
|
||||
public function form(Request $request): JsonResponse|TeacherAttendanceFormResource
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
return new TeacherAttendanceFormResource(
|
||||
$this->queryService->teacherAttendanceFormData(
|
||||
auth()->id(),
|
||||
$guard,
|
||||
(int)$request->query('class_section_id', 0)
|
||||
)
|
||||
);
|
||||
@@ -47,12 +52,30 @@ class TeacherAttendanceApiController extends Controller
|
||||
|
||||
public function submit(TeacherSubmitAttendanceRequest $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user === null) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
try {
|
||||
return response()->json(
|
||||
$this->attendanceService->submitTeacherAttendance(auth()->user(), $request->validated())
|
||||
$this->attendanceService->submitTeacherAttendance($user, $request->validated())
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
@@ -2,69 +2,83 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\ApiLoginSecurityService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use PHPOpenSourceSaver\JWTAuth\Facades\JWTAuth;
|
||||
|
||||
class AuthController extends BaseApiController
|
||||
{
|
||||
public function login(Request $request): JsonResponse
|
||||
public function login(Request $request, ApiLoginSecurityService $security): JsonResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
$payload = $request->all();
|
||||
if ($request->isJson() && ($payload === [] || $payload === null)) {
|
||||
$decoded = json_decode((string) $request->getContent(), true);
|
||||
$payload = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
$email = (string) $request->input('email');
|
||||
$password = (string) $request->input('password');
|
||||
// Match CodeIgniter apiLogin: raw email/password (no trim); empty check is identical to CI `!$email || !$password`.
|
||||
$email = (string) ($payload['email'] ?? '');
|
||||
$password = (string) ($payload['password'] ?? '');
|
||||
|
||||
if ($email === '' || $password === '') {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Email and password are required.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$ip = $request->ip();
|
||||
if ($security->isIpBlocked((string) $ip)) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Too many failed attempts from your IP. Please try again later.',
|
||||
], 429);
|
||||
}
|
||||
|
||||
$user = User::query()->where('email', $email)->first();
|
||||
if (!$user || !ci_password_verify($password, (string) $user->password)) {
|
||||
return $this->respondError('Invalid credentials.', 401);
|
||||
if (!$user) {
|
||||
$security->logIpAttempt((string) $ip);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Invalid email or password.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
if ((int) ($user->is_verified ?? 0) !== 1) {
|
||||
return $this->respondError('Account not verified.', 403);
|
||||
if ($user->is_suspended) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Account suspended. Please reset your password.',
|
||||
], 403);
|
||||
}
|
||||
|
||||
if (strcasecmp((string) ($user->status ?? ''), 'Active') !== 0) {
|
||||
return $this->respondError('Account is inactive.', 403);
|
||||
if (! ci_password_verify($password, (string) $user->password)) {
|
||||
$security->handleFailedLogin($user, $email, (string) $ip);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Invalid email or password.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$jwtToken = JWTAuth::fromUser($user);
|
||||
$sanctumToken = $user->createToken('api')->plainTextToken;
|
||||
$roles = $user->roles()
|
||||
->where('roles.is_active', 1)
|
||||
->pluck('roles.name')
|
||||
->values()
|
||||
->all();
|
||||
$security->resetFailedAttempts($user);
|
||||
$security->logSuccessfulLogin($user->fresh(), $request);
|
||||
|
||||
return $this->respondSuccess([
|
||||
'user' => [
|
||||
'id' => (int) $user->id,
|
||||
'firstname' => $user->firstname,
|
||||
'lastname' => $user->lastname,
|
||||
'email' => $user->email,
|
||||
'roles' => $roles,
|
||||
],
|
||||
'jwt' => [
|
||||
'access_token' => $jwtToken,
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => (int) config('jwt.ttl') * 60,
|
||||
],
|
||||
'sanctum' => [
|
||||
'access_token' => $sanctumToken,
|
||||
'token_type' => 'bearer',
|
||||
],
|
||||
], 'Authenticated.');
|
||||
$fresh = $user->fresh();
|
||||
if (!$fresh) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Invalid email or password.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$jwtToken = JWTAuth::fromUser($fresh);
|
||||
|
||||
return response()->json($security->buildLoginResponse($fresh, $jwtToken));
|
||||
}
|
||||
|
||||
public function refresh(Request $request): JsonResponse
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Auth\LoginSessionRequest;
|
||||
use App\Http\Requests\Auth\SetRoleSessionRequest;
|
||||
use App\Models\User;
|
||||
use App\Services\ApplicationUrlService;
|
||||
use App\Services\Auth\ApiLoginSecurityService;
|
||||
use App\Services\Auth\AuthSessionService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Session (cookie) endpoints for SPA — JSON alongside JWT on /api/login.
|
||||
*
|
||||
* Routes: GET login, POST user/login, GET logout, GET select-role, POST set-role (registered on web middleware).
|
||||
*/
|
||||
class AuthSessionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private ApiLoginSecurityService $security,
|
||||
private AuthSessionService $sessionAuth,
|
||||
private ApplicationUrlService $urls,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* CI `loginMask` — login page bootstrap / redirect when already authenticated.
|
||||
*/
|
||||
public function loginMask(Request $request): JsonResponse
|
||||
{
|
||||
$redirectTo = $this->sessionAuth->sanitizeRedirectTarget(
|
||||
(string) ($request->query('redirect_to') ?? ''),
|
||||
);
|
||||
|
||||
if (! Auth::guard('web')->check()) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => false,
|
||||
'redirect_to' => $redirectTo,
|
||||
]);
|
||||
}
|
||||
|
||||
/** @var list<string>|null $roles */
|
||||
$roles = session('roles');
|
||||
$roles = is_array($roles) ? array_values(array_filter(array_map('strval', $roles))) : [];
|
||||
$currentRole = session('role');
|
||||
|
||||
if ($roles !== [] && count($roles) > 1 && ! $currentRole) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => true,
|
||||
'next_url' => $this->urls->webSelectRoleUrl(false),
|
||||
'roles' => $roles,
|
||||
'pending_redirect' => session('post_login_redirect'),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($redirectTo !== null) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => true,
|
||||
'next_url' => $redirectTo,
|
||||
]);
|
||||
}
|
||||
|
||||
$pick = $currentRole !== null && $currentRole !== ''
|
||||
? [(string) $currentRole]
|
||||
: $roles;
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => true,
|
||||
'next_url' => $this->sessionAuth->dashboardRouteForRoles($pick),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `login` — POST /user/login.
|
||||
*/
|
||||
public function login(LoginSessionRequest $request): JsonResponse
|
||||
{
|
||||
$email = (string) $request->validated('email');
|
||||
$password = (string) $request->validated('password');
|
||||
$redirectRaw = $request->validated('redirect_to');
|
||||
$sanitizedRedirect = $redirectRaw !== null
|
||||
? $this->sessionAuth->sanitizeRedirectTarget((string) $redirectRaw)
|
||||
: null;
|
||||
|
||||
$ip = (string) $request->ip();
|
||||
|
||||
if ($this->security->isIpBlocked($ip)) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Too many failed attempts from your IP. Please try again later.',
|
||||
], 429);
|
||||
}
|
||||
|
||||
$user = User::query()->where('email', $email)->first();
|
||||
|
||||
if (! $user) {
|
||||
$this->security->logIpAttempt($ip);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'The email and password combination you entered is invalid. Please try again.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
if ($user->is_suspended) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Account suspended. Please check your email to reset your password.',
|
||||
], 403);
|
||||
}
|
||||
|
||||
if (! ci_password_verify($password, (string) $user->password)) {
|
||||
$this->security->handleFailedLogin($user, $email, $ip);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'The email and password combination you entered is invalid. Please try again.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$fresh = $user->fresh();
|
||||
if (! $fresh) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'The email and password combination you entered is invalid. Please try again.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$this->security->resetFailedAttempts($fresh);
|
||||
$this->security->logSuccessfulLogin($fresh, $request);
|
||||
|
||||
$dest = $this->sessionAuth->resolvePostLoginDestination($fresh, $sanitizedRedirect);
|
||||
|
||||
if (($dest['kind'] ?? '') === 'no_roles') {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => (string) ($dest['reason'] ?? 'Role not assigned. Please contact support.'),
|
||||
], 403);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'requires_role_selection' => ($dest['kind'] ?? '') === 'select_role',
|
||||
'roles' => $dest['roles'] ?? null,
|
||||
'next_url' => $dest['redirect_url'] ?? $this->urls->docsHomeUrl(false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `logout` — GET /logout.
|
||||
*/
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
$userId = Auth::guard('web')->id();
|
||||
$email = Auth::guard('web')->user()?->email ?? session('user_email');
|
||||
|
||||
$this->sessionAuth->logLogout($userId ? (int) $userId : null, $email ? (string) $email : null);
|
||||
|
||||
Auth::guard('web')->logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'next_url' => $this->urls->docsHomeUrl(false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `selectRole` — GET /select-role.
|
||||
*/
|
||||
public function selectRole(Request $request): JsonResponse
|
||||
{
|
||||
if (! Auth::guard('web')->check()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'No roles available.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
/** @var list<string>|null $roles */
|
||||
$roles = session('roles');
|
||||
$roles = is_array($roles) ? array_values(array_filter(array_map('strval', $roles))) : [];
|
||||
|
||||
if ($roles === []) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'No roles available.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'roles' => $roles,
|
||||
'pending_redirect' => session('post_login_redirect'),
|
||||
'redirect_to_query' => $this->sessionAuth->sanitizeRedirectTarget(
|
||||
(string) ($request->query('redirect_to') ?? ''),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `setRole` — POST /set-role.
|
||||
*/
|
||||
public function setRole(SetRoleSessionRequest $request): JsonResponse
|
||||
{
|
||||
if (! Auth::guard('web')->check()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Unauthorized.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$selectedRole = (string) $request->validated('selected_role');
|
||||
|
||||
/** @var list<string>|null $available */
|
||||
$available = session('roles');
|
||||
$available = is_array($available) ? array_values(array_filter(array_map('strval', $available))) : [];
|
||||
|
||||
if ($available === [] || ! in_array($selectedRole, $available, true)) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Invalid role selected.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
$redirectRaw = $request->validated('redirect_to');
|
||||
$redirectTo = $redirectRaw !== null
|
||||
? $this->sessionAuth->sanitizeRedirectTarget((string) $redirectRaw)
|
||||
: null;
|
||||
|
||||
if ($redirectTo === null) {
|
||||
$redirectTo = $this->sessionAuth->sanitizeRedirectTarget(
|
||||
(string) (session('post_login_redirect') ?? ''),
|
||||
);
|
||||
}
|
||||
|
||||
session(['role' => $selectedRole]);
|
||||
session()->forget('post_login_redirect');
|
||||
|
||||
$next = $redirectTo ?? $this->sessionAuth->dashboardRouteForRoles([$selectedRole]);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'role' => $selectedRole,
|
||||
'next_url' => $next,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Security\IpBanIndexRequest;
|
||||
use App\Http\Requests\Security\IpBanRequest;
|
||||
use App\Http\Requests\Security\IpUnbanRequest;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Resources\Auth\RegisterResource;
|
||||
use App\Services\Auth\CodeIgniterApiRegistrationService;
|
||||
use App\Services\Auth\RegistrationCaptchaService;
|
||||
use App\Services\Auth\RegistrationService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -31,6 +32,11 @@ class RegisterController extends BaseApiController
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
// CodeIgniter-style JSON register (POST api/v1/register): password + no captcha field.
|
||||
if (! $request->has('captcha') && $request->filled('password')) {
|
||||
return app(CodeIgniterApiRegistrationService::class)->registerResponse($request);
|
||||
}
|
||||
|
||||
if (app()->runningUnitTests() && $request->header('X-Debug-Request') === '1') {
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Roles\AssignUserRolesRequest;
|
||||
use App\Http\Requests\Roles\PermissionStoreRequest;
|
||||
use App\Http\Requests\Roles\PermissionUpdateRequest;
|
||||
use App\Http\Requests\Roles\RoleListRequest;
|
||||
use App\Http\Requests\Roles\RolePermissionUpdateRequest;
|
||||
use App\Http\Requests\Roles\RoleStoreRequest;
|
||||
use App\Http\Requests\Roles\RoleUpdateRequest;
|
||||
use App\Http\Requests\Roles\UserRoleListRequest;
|
||||
use App\Http\Resources\Roles\PermissionResource;
|
||||
use App\Http\Resources\Roles\RolePermissionResource;
|
||||
use App\Http\Resources\Roles\RoleResource;
|
||||
use App\Http\Resources\Roles\UserWithRolesResource;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Services\Roles\PermissionCrudService;
|
||||
use App\Services\Roles\RoleAssignmentService;
|
||||
use App\Services\Roles\RoleCrudService;
|
||||
use App\Services\Roles\RolePermissionService;
|
||||
use App\Services\Roles\RoleQueryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class RolePermissionController extends BaseApiController
|
||||
{
|
||||
public function __construct(
|
||||
private RoleQueryService $queryService,
|
||||
private RoleAssignmentService $assignmentService,
|
||||
private RolePermissionService $permissionService,
|
||||
private RoleCrudService $roleCrudService,
|
||||
private PermissionCrudService $permissionCrudService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function roles(RoleListRequest $request): JsonResponse
|
||||
{
|
||||
$roles = $this->queryService->listRoles($request->validated());
|
||||
|
||||
return $this->success([
|
||||
'roles' => RoleResource::collection($roles->items()),
|
||||
'meta' => [
|
||||
'total' => $roles->total(),
|
||||
'per_page' => $roles->perPage(),
|
||||
'current_page' => $roles->currentPage(),
|
||||
'last_page' => $roles->lastPage(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function showRole(int $roleId): JsonResponse
|
||||
{
|
||||
$role = Role::query()->find($roleId);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'role' => new RoleResource($role),
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeRole(RoleStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$role = $this->roleCrudService->create($request->validated());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Role store failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to create role.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'role' => new RoleResource($role),
|
||||
], 'Role created successfully.', Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
public function updateRole(RoleUpdateRequest $request, int $roleId): JsonResponse
|
||||
{
|
||||
$role = Role::query()->find($roleId);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$role = $this->roleCrudService->update($role, $request->validated());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Role update failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to update role.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'role' => new RoleResource($role),
|
||||
], 'Role updated successfully.');
|
||||
}
|
||||
|
||||
public function deleteRole(int $roleId): JsonResponse
|
||||
{
|
||||
$role = Role::query()->find($roleId);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->roleCrudService->delete($role);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Role delete failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to delete role.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success(null, 'Role deleted successfully.');
|
||||
}
|
||||
|
||||
public function users(UserRoleListRequest $request): JsonResponse
|
||||
{
|
||||
$users = $this->queryService->listUsersWithRoles($request->validated());
|
||||
|
||||
return $this->success([
|
||||
'users' => UserWithRolesResource::collection($users->items()),
|
||||
'meta' => [
|
||||
'total' => $users->total(),
|
||||
'per_page' => $users->perPage(),
|
||||
'current_page' => $users->currentPage(),
|
||||
'last_page' => $users->lastPage(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function assignRoles(AssignUserRolesRequest $request, int $userId): JsonResponse
|
||||
{
|
||||
$actorId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actorId instanceof JsonResponse) {
|
||||
return $actorId;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->assignmentService->assignRoles(
|
||||
$userId,
|
||||
(array) ($request->validated()['role_ids'] ?? []),
|
||||
$actorId
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Assign roles failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to update roles.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Failed to update roles.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'role_names' => $result['role_names'] ?? [],
|
||||
], 'Roles updated successfully.');
|
||||
}
|
||||
|
||||
public function permissions(): JsonResponse
|
||||
{
|
||||
$permissions = $this->permissionService->listPermissions();
|
||||
|
||||
return $this->success([
|
||||
'permissions' => PermissionResource::collection($permissions),
|
||||
]);
|
||||
}
|
||||
|
||||
public function showPermission(int $permissionId): JsonResponse
|
||||
{
|
||||
$permission = Permission::query()->find($permissionId);
|
||||
if (!$permission) {
|
||||
return $this->error('Permission not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'permission' => new PermissionResource($permission),
|
||||
]);
|
||||
}
|
||||
|
||||
public function storePermission(PermissionStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$permission = $this->permissionCrudService->create($request->validated());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Permission store failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to create permission.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'permission' => new PermissionResource($permission),
|
||||
], 'Permission created successfully.', Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
public function updatePermission(PermissionUpdateRequest $request, int $permissionId): JsonResponse
|
||||
{
|
||||
$permission = Permission::query()->find($permissionId);
|
||||
if (!$permission) {
|
||||
return $this->error('Permission not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$permission = $this->permissionCrudService->update($permission, $request->validated());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Permission update failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to update permission.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'permission' => new PermissionResource($permission),
|
||||
], 'Permission updated successfully.');
|
||||
}
|
||||
|
||||
public function deletePermission(int $permissionId): JsonResponse
|
||||
{
|
||||
$permission = Permission::query()->find($permissionId);
|
||||
if (!$permission) {
|
||||
return $this->error('Permission not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->permissionCrudService->delete($permission);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Permission delete failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to delete permission.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success(null, 'Permission deleted successfully.');
|
||||
}
|
||||
|
||||
public function rolePermissions(int $roleId): JsonResponse
|
||||
{
|
||||
$rows = $this->permissionService->listRolePermissions($roleId);
|
||||
|
||||
return $this->success([
|
||||
'permissions' => RolePermissionResource::collection($rows),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateRolePermissions(RolePermissionUpdateRequest $request, int $roleId): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->permissionService->saveRolePermissions($roleId, $request->validated()['permissions'] ?? []);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Role permissions update failed: ' . $e->getMessage());
|
||||
return $this->error('Failed to update role permissions.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success(null, 'Permissions saved successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Roles\RoleSwitchRequest;
|
||||
use App\Services\Roles\RoleSwitchService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class RoleSwitcherController extends BaseApiController
|
||||
{
|
||||
public function __construct(private RoleSwitchService $switchService)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$roles = $this->switchService->getUserRoleNames($guard);
|
||||
if (empty($roles)) {
|
||||
return $this->error('No roles assigned to this user.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'roles' => $roles,
|
||||
]);
|
||||
}
|
||||
|
||||
public function switch(RoleSwitchRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$role = (string) $request->validated()['role'];
|
||||
$route = $this->switchService->switchRole($role);
|
||||
|
||||
return $this->success([
|
||||
'role' => $role,
|
||||
'dashboard_route' => $route,
|
||||
], 'Role switched successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Please log in first.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Config\SessionTimeout;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\ApplicationUrlService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Session idle timeout checks (web session cookie).
|
||||
*/
|
||||
class SessionTimeoutController extends Controller
|
||||
{
|
||||
/** CI-compatible session key */
|
||||
private const SESSION_KEY = 'last_activity';
|
||||
|
||||
public function __construct(
|
||||
private ApplicationUrlService $urls,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* CI nested routes: SessionController::getTimeoutConfig shape (URLs point at this app).
|
||||
*/
|
||||
public function getTimeoutConfig(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'timeout' => SessionTimeout::TIMEOUT_DURATION,
|
||||
'warning_time' => SessionTimeout::WARNING_THRESHOLD,
|
||||
'check_interval' => SessionTimeout::CHECK_INTERVAL,
|
||||
'logout_url' => $this->urls->webLogoutUrl(),
|
||||
'keep_alive_url' => $this->urls->webSessionPingUrl(),
|
||||
'check_url' => $this->urls->webSessionCheckTimeoutUrl(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function checkTimeout(Request $request): JsonResponse
|
||||
{
|
||||
$session = $request->session();
|
||||
|
||||
if (! $session->has(self::SESSION_KEY)) {
|
||||
return $this->expireSession($request);
|
||||
}
|
||||
|
||||
$lastActivity = (int) $session->get(self::SESSION_KEY);
|
||||
$elapsed = time() - $lastActivity;
|
||||
|
||||
if ($elapsed > SessionTimeout::TIMEOUT_DURATION) {
|
||||
return $this->expireSession($request);
|
||||
}
|
||||
|
||||
if ($elapsed > SessionTimeout::WARNING_THRESHOLD) {
|
||||
return response()->json([
|
||||
'status' => 'warning',
|
||||
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'active',
|
||||
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed,
|
||||
]);
|
||||
}
|
||||
|
||||
public function pingActivity(Request $request): JsonResponse
|
||||
{
|
||||
$session = $request->session();
|
||||
|
||||
if (! $session->has(self::SESSION_KEY)
|
||||
|| (time() - (int) $session->get(self::SESSION_KEY)) > SessionTimeout::TIMEOUT_DURATION) {
|
||||
return $this->expireSession($request);
|
||||
}
|
||||
|
||||
$session->put(self::SESSION_KEY, time());
|
||||
|
||||
return response()->json([
|
||||
'status' => 'active',
|
||||
'time_remaining' => SessionTimeout::TIMEOUT_DURATION,
|
||||
]);
|
||||
}
|
||||
|
||||
private function expireSession(Request $request): JsonResponse
|
||||
{
|
||||
$request->session()->flash('error', 'Your session has expired due to inactivity.');
|
||||
$request->session()->forget(self::SESSION_KEY);
|
||||
|
||||
Auth::guard('web')->logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return response()->json([
|
||||
'status' => 'expired',
|
||||
'redirect' => $this->urls->webLoginUrl(),
|
||||
'message' => 'Your session has expired due to inactivity.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\BadgeScan;
|
||||
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Services\BadgeScan\BadgeScanService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class BadgeScanController extends BaseApiController
|
||||
{
|
||||
public function __construct(
|
||||
private BadgeScanService $badgeScan,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public kiosk endpoint — POST JSON or form (legacy CI RFIDController::process).
|
||||
*/
|
||||
public function scan(Request $request): JsonResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'badge_scan' => ['required', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
$result = $this->badgeScan->processScan($validator->validated()['badge_scan']);
|
||||
|
||||
if (! $result['recognized']) {
|
||||
return $this->error($result['message'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'recognized' => true,
|
||||
'user_id' => $result['user_id'] ?? null,
|
||||
'display_name' => $result['display_name'] ?? null,
|
||||
], $result['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticated scan log listing (legacy CI RFIDController::log).
|
||||
*/
|
||||
public function logs(): JsonResponse
|
||||
{
|
||||
return $this->success([
|
||||
'logs' => $this->badgeScan->scanLogRows(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -22,14 +22,30 @@ class BadgeController extends Controller
|
||||
|
||||
public function generatePdf(Request $request)
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'user_ids' => ['required', 'array', 'min:1'],
|
||||
'user_ids.*' => ['integer', 'min:1'],
|
||||
'user_ids' => ['nullable', 'array'],
|
||||
'user_ids.*' => ['integer', 'exists:users,id'],
|
||||
'student_ids' => ['nullable', 'array'],
|
||||
'student_ids.*' => ['integer', 'exists:students,id'],
|
||||
'school_year' => ['nullable', 'string', 'max:50'],
|
||||
'roles' => ['nullable', 'array'],
|
||||
'classes' => ['nullable', 'array'],
|
||||
]);
|
||||
|
||||
$validator->after(function ($validator): void {
|
||||
$data = $validator->getData();
|
||||
$users = array_values(array_filter((array) ($data['user_ids'] ?? []), static fn ($v) => (int) $v > 0));
|
||||
$students = array_values(array_filter((array) ($data['student_ids'] ?? []), static fn ($v) => (int) $v > 0));
|
||||
if ($users === [] && $students === []) {
|
||||
$validator->errors()->add('user_ids', 'Provide at least one user id or student id.');
|
||||
}
|
||||
});
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
@@ -40,11 +56,12 @@ class BadgeController extends Controller
|
||||
$data = $validator->validated();
|
||||
|
||||
return $this->badgePdfService->generate(
|
||||
studentIds: $data['student_ids'] ?? [],
|
||||
userIds: $data['user_ids'] ?? [],
|
||||
schoolYear: $data['school_year'] ?? null,
|
||||
rolesMap: $data['roles'] ?? [],
|
||||
classesMap: $data['classes'] ?? [],
|
||||
actorId: optional($request->user())->id
|
||||
actorId: $guard
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,7 +71,7 @@ class BadgeController extends Controller
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'data' => $this->badgePrintLogService->getStatus(
|
||||
$this->parseUserIds($request),
|
||||
$this->parseCombinedBadgeIds($request),
|
||||
$request->input('school_year')
|
||||
),
|
||||
]);
|
||||
@@ -69,14 +86,30 @@ class BadgeController extends Controller
|
||||
public function logPrint(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'user_ids' => ['required', 'array', 'min:1'],
|
||||
'user_ids.*' => ['integer', 'min:1'],
|
||||
'user_ids' => ['nullable', 'array'],
|
||||
'user_ids.*' => ['integer', 'exists:users,id'],
|
||||
'student_ids' => ['nullable', 'array'],
|
||||
'student_ids.*' => ['integer', 'exists:students,id'],
|
||||
'school_year' => ['nullable', 'string', 'max:50'],
|
||||
'roles' => ['nullable', 'array'],
|
||||
'classes' => ['nullable', 'array'],
|
||||
]);
|
||||
|
||||
$validator->after(function ($validator): void {
|
||||
$data = $validator->getData();
|
||||
$users = array_values(array_filter((array) ($data['user_ids'] ?? []), static fn ($v) => (int) $v > 0));
|
||||
$students = array_values(array_filter((array) ($data['student_ids'] ?? []), static fn ($v) => (int) $v > 0));
|
||||
if ($users === [] && $students === []) {
|
||||
$validator->errors()->add('user_ids', 'Provide at least one user id or student id.');
|
||||
}
|
||||
});
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
@@ -87,8 +120,11 @@ class BadgeController extends Controller
|
||||
$data = $validator->validated();
|
||||
|
||||
$inserted = $this->badgePrintLogService->log(
|
||||
userIds: $data['user_ids'] ?? [],
|
||||
actorId: optional($request->user())->id,
|
||||
userIds: array_values(array_unique(array_merge(
|
||||
$data['user_ids'] ?? [],
|
||||
$data['student_ids'] ?? []
|
||||
))),
|
||||
actorId: $guard,
|
||||
schoolYear: $data['school_year'] ?? null,
|
||||
rolesMap: $data['roles'] ?? [],
|
||||
classesMap: $data['classes'] ?? []
|
||||
@@ -112,24 +148,75 @@ class BadgeController extends Controller
|
||||
'ok' => true,
|
||||
'data' => $this->badgeFormDataService->build(
|
||||
schoolYear: $request->input('school_year'),
|
||||
selectedUserIds: $this->parseUserIds($request),
|
||||
selectedUserIds: $this->parseStaffUserIds($request),
|
||||
activeRole: $request->input('active_role')
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
private function parseUserIds(Request $request): array
|
||||
/**
|
||||
* Staff user IDs for the badge picker (`users.id`).
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
private function parseStaffUserIds(Request $request): array
|
||||
{
|
||||
$userIds = $request->input('user_ids', $request->query('user_ids', []));
|
||||
$ids = $request->input('user_ids', $request->query('user_ids', []));
|
||||
|
||||
if (is_string($userIds)) {
|
||||
$userIds = array_filter(array_map('trim', explode(',', $userIds)), 'strlen');
|
||||
} elseif (!is_array($userIds)) {
|
||||
$userIds = $userIds ? [$userIds] : [];
|
||||
if (is_string($ids)) {
|
||||
$ids = array_filter(array_map('trim', explode(',', $ids)), 'strlen');
|
||||
} elseif (!is_array($ids)) {
|
||||
$ids = $ids ? [$ids] : [];
|
||||
}
|
||||
|
||||
$userIds = array_values(array_unique(array_map(static fn ($v) => (int) $v, $userIds)));
|
||||
$ids = array_values(array_unique(array_map(static fn ($v) => (int) $v, $ids)));
|
||||
|
||||
return array_values(array_filter($userIds, static fn ($v) => $v > 0));
|
||||
return array_values(array_filter($ids, static fn ($v) => $v > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined `users.id` and `students.id` for print-status (same numeric space as stored in logs).
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
private function parseCombinedBadgeIds(Request $request): array
|
||||
{
|
||||
return array_values(array_unique(array_merge(
|
||||
$this->parseStaffUserIds($request),
|
||||
$this->parseStudentIds($request)
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Student primary keys (`students.id`) from query or body.
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
private function parseStudentIds(Request $request): array
|
||||
{
|
||||
$ids = $request->input('student_ids', $request->query('student_ids', []));
|
||||
|
||||
if (is_string($ids)) {
|
||||
$ids = array_filter(array_map('trim', explode(',', $ids)), 'strlen');
|
||||
} elseif (!is_array($ids)) {
|
||||
$ids = $ids ? [$ids] : [];
|
||||
}
|
||||
|
||||
$ids = array_values(array_unique(array_map(static fn ($v) => (int) $v, $ids)));
|
||||
|
||||
return array_values(array_filter($ids, static fn ($v) => $v > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\ClassPreparation;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\ClassPreparation\ClassPreparationAdjustmentRequest;
|
||||
use App\Http\Requests\ClassPreparation\ClassPreparationIndexRequest;
|
||||
use App\Http\Requests\ClassPreparation\ClassPreparationMarkPrintedRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\ClassProgress;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\ClassProgress\ClassProgressIndexRequest;
|
||||
use App\Http\Requests\ClassProgress\ClassProgressMetaRequest;
|
||||
use App\Http\Requests\ClassProgress\ClassProgressStoreRequest;
|
||||
@@ -12,6 +12,7 @@ use App\Http\Resources\ClassProgress\ClassProgressReportResource;
|
||||
use App\Http\Resources\ClassProgress\ClassProgressShowResource;
|
||||
use App\Models\ClassProgressAttachment;
|
||||
use App\Models\ClassProgressReport;
|
||||
use App\Models\User;
|
||||
use App\Services\ClassProgress\ClassProgressAttachmentService;
|
||||
use App\Services\ClassProgress\ClassProgressMetaService;
|
||||
use App\Services\ClassProgress\ClassProgressMutationService;
|
||||
@@ -19,6 +20,7 @@ use App\Services\ClassProgress\ClassProgressQueryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class ClassProgressController extends BaseApiController
|
||||
{
|
||||
@@ -40,7 +42,7 @@ class ClassProgressController extends BaseApiController
|
||||
$payload = [
|
||||
'subject_sections' => $this->metaService->subjectSections(),
|
||||
'status_options' => $this->metaService->statusOptions(),
|
||||
'sunday_options' => $this->metaService->sundayOptions($sundayCount),
|
||||
'sunday_options' => $this->metaService->sundayOptionsAlignedWithCi($sundayCount),
|
||||
'curriculum' => $this->metaService->curriculumOptions($classId ? (int) $classId : null),
|
||||
];
|
||||
|
||||
@@ -49,8 +51,13 @@ class ClassProgressController extends BaseApiController
|
||||
|
||||
public function index(ClassProgressIndexRequest $request): JsonResponse
|
||||
{
|
||||
$auth = $this->requireAuthenticatedUser($request->user());
|
||||
if ($auth instanceof JsonResponse) {
|
||||
return $auth;
|
||||
}
|
||||
|
||||
$filters = $request->validated();
|
||||
$paginator = $this->queryService->listReports($request->user(), $filters);
|
||||
$paginator = $this->queryService->listReports($auth, $filters);
|
||||
|
||||
if (!empty($filters['group_by_week'])) {
|
||||
$grouped = ClassProgressGroupCollection::fromPaginator($paginator);
|
||||
@@ -70,10 +77,23 @@ class ClassProgressController extends BaseApiController
|
||||
|
||||
public function store(ClassProgressStoreRequest $request): JsonResponse
|
||||
{
|
||||
$auth = $this->requireAuthenticatedUser($request->user());
|
||||
if ($auth instanceof JsonResponse) {
|
||||
return $auth;
|
||||
}
|
||||
|
||||
try {
|
||||
$filesBySubject = $request->filesBySubject();
|
||||
$reports = $this->mutationService->createReports($request->user(), $request->validated(), $filesBySubject);
|
||||
$reports = $this->mutationService->createReports($auth, $request->validated(), $filesBySubject);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
if ($e->getMessage() === 'CONFIRM_OVERWRITE') {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'A progress report already exists for this week. Resubmit with confirm_overwrite=true to replace it.',
|
||||
'data' => ['requires_confirmation' => true],
|
||||
], 409);
|
||||
}
|
||||
|
||||
return $this->respondError($e->getMessage(), 422);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Failed to create class progress reports.', [
|
||||
@@ -87,7 +107,12 @@ class ClassProgressController extends BaseApiController
|
||||
|
||||
public function show(ClassProgressReport $class_progress): JsonResponse
|
||||
{
|
||||
$weeklyReports = $this->queryService->weeklyReports($this->laravelRequest->user(), $class_progress);
|
||||
$auth = $this->requireAuthenticatedUser($this->laravelRequest->user());
|
||||
if ($auth instanceof JsonResponse) {
|
||||
return $auth;
|
||||
}
|
||||
|
||||
$weeklyReports = $this->queryService->weeklyReports($auth, $class_progress);
|
||||
|
||||
return $this->respondSuccess(
|
||||
new ClassProgressShowResource([
|
||||
@@ -164,4 +189,17 @@ class ClassProgressController extends BaseApiController
|
||||
|
||||
return response()->download($path, basename($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $user
|
||||
* @return User|JsonResponse
|
||||
*/
|
||||
private function requireAuthenticatedUser($user): User|JsonResponse
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
return $this->respondError('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Classes;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Classes\ClassSectionIndexRequest;
|
||||
use App\Http\Requests\Classes\ClassSectionStoreRequest;
|
||||
use App\Http\Requests\Classes\ClassSectionUpdateRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Communication;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Services\Communication\CommunicationFamilyService;
|
||||
use App\Services\Communication\CommunicationPreviewService;
|
||||
use App\Services\Communication\CommunicationSendService;
|
||||
@@ -123,6 +123,11 @@ class CommunicationController extends BaseApiController
|
||||
], 404);
|
||||
}
|
||||
|
||||
$senderId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($senderId instanceof JsonResponse) {
|
||||
return $senderId;
|
||||
}
|
||||
|
||||
$result = $this->sendService->send([
|
||||
'student_id' => $studentId,
|
||||
'family_id' => $familyId,
|
||||
@@ -133,7 +138,7 @@ class CommunicationController extends BaseApiController
|
||||
'cc' => $cc,
|
||||
'bcc' => $bcc,
|
||||
'student_name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')),
|
||||
'sent_by' => (int) (auth()->id() ?? 0),
|
||||
'sent_by' => $senderId,
|
||||
]);
|
||||
|
||||
if (!$result['ok']) {
|
||||
@@ -175,4 +180,17 @@ class CommunicationController extends BaseApiController
|
||||
}
|
||||
return 'Teacher';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\CompetitionScores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Models\Competition;
|
||||
use App\Services\CompetitionScores\CompetitionScoresContextService;
|
||||
use App\Services\CompetitionScores\CompetitionScoresQueryService;
|
||||
@@ -33,8 +33,12 @@ class CompetitionScoresController extends BaseApiController
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
[$assignments, $schoolYear, $semester] = $this->contextService->getTeacherContext($userId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
[$assignments, $schoolYear, $semester] = $this->contextService->getTeacherContext($guard);
|
||||
|
||||
$activeClassId = $this->contextService->resolveActiveClassId(
|
||||
$assignments,
|
||||
@@ -80,8 +84,12 @@ class CompetitionScoresController extends BaseApiController
|
||||
|
||||
public function edit(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
[$assignments, $schoolYear, $semester] = $this->contextService->getTeacherContext($userId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
[$assignments, $schoolYear, $semester] = $this->contextService->getTeacherContext($guard);
|
||||
$allowedClassIds = $this->contextService->getAllowedClassIds($assignments);
|
||||
|
||||
if (empty($allowedClassIds)) {
|
||||
@@ -146,8 +154,12 @@ class CompetitionScoresController extends BaseApiController
|
||||
|
||||
public function save(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
[$assignments] = $this->contextService->getTeacherContext($userId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
[$assignments] = $this->contextService->getTeacherContext($guard);
|
||||
$allowedClassIds = $this->contextService->getAllowedClassIds($assignments);
|
||||
|
||||
if (empty($allowedClassIds)) {
|
||||
@@ -209,4 +221,17 @@ class CompetitionScoresController extends BaseApiController
|
||||
'savedCount' => count($cleanScores),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Core;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Validation\Validator as ValidatorContract;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class BaseApiController extends Controller
|
||||
{
|
||||
protected Request $laravelRequest;
|
||||
protected CiRequestAdapter $request;
|
||||
protected ValidatorContract|null $validator = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->laravelRequest = request();
|
||||
$this->request = new CiRequestAdapter($this->laravelRequest);
|
||||
}
|
||||
|
||||
protected function success($data = null, string $message = 'Success', int $code = Response::HTTP_OK): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => $message,
|
||||
'data' => $data,
|
||||
], $code);
|
||||
}
|
||||
|
||||
protected function error(string $message = 'An error occurred', int $code = Response::HTTP_BAD_REQUEST, ?array $errors = null): JsonResponse
|
||||
{
|
||||
$payload = [
|
||||
'status' => false,
|
||||
'message' => $message,
|
||||
];
|
||||
if (!empty($errors)) {
|
||||
$payload['errors'] = $errors;
|
||||
}
|
||||
|
||||
return response()->json($payload, $code);
|
||||
}
|
||||
|
||||
protected function respondSuccess($data = null, string $message = 'Success', int $code = Response::HTTP_OK): JsonResponse
|
||||
{
|
||||
return $this->success($data, $message, $code);
|
||||
}
|
||||
|
||||
protected function respondCreated($data = null, string $message = 'Resource created successfully'): JsonResponse
|
||||
{
|
||||
return $this->success($data, $message, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
protected function respondDeleted($data = null, string $message = 'Resource deleted successfully'): JsonResponse
|
||||
{
|
||||
return $this->success($data, $message, Response::HTTP_OK);
|
||||
}
|
||||
|
||||
protected function respondError(string $message = 'An error occurred', int $code = Response::HTTP_BAD_REQUEST): JsonResponse
|
||||
{
|
||||
return $this->error($message, $code);
|
||||
}
|
||||
|
||||
protected function respondValidationError(array $errors, string $message = 'Validation failed'): JsonResponse
|
||||
{
|
||||
return $this->error($message, Response::HTTP_UNPROCESSABLE_ENTITY, $errors);
|
||||
}
|
||||
|
||||
protected function validateRequest(array $data, array $rules): array
|
||||
{
|
||||
$normalized = [];
|
||||
foreach ($rules as $field => $ruleSet) {
|
||||
$normalized[$field] = $this->normalizeRules($ruleSet);
|
||||
}
|
||||
|
||||
$validator = Validator::make($data, $normalized);
|
||||
$this->validator = $validator;
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $validator->errors()->toArray();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function validate(array $rules): bool
|
||||
{
|
||||
$payload = $this->payloadData();
|
||||
$errors = $this->validateRequest($payload, $rules);
|
||||
return empty($errors);
|
||||
}
|
||||
|
||||
protected function payloadData(): array
|
||||
{
|
||||
$json = json_decode($this->laravelRequest->getContent() ?: '', true);
|
||||
if (is_array($json)) {
|
||||
return $json;
|
||||
}
|
||||
return array_merge($this->laravelRequest->query->all(), $this->laravelRequest->request->all());
|
||||
}
|
||||
|
||||
protected function normalizeRules(array|string $ruleSet): array|string
|
||||
{
|
||||
if (is_array($ruleSet)) {
|
||||
return $ruleSet;
|
||||
}
|
||||
$parts = explode('|', $ruleSet);
|
||||
$result = [];
|
||||
foreach ($parts as $part) {
|
||||
$part = trim($part);
|
||||
if ($part === '') {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^max_length\\[(\\d+)\\]$/', $part, $m)) {
|
||||
$result[] = 'max:' . $m[1];
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^min_length\\[(\\d+)\\]$/', $part, $m)) {
|
||||
$result[] = 'min:' . $m[1];
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^in_list\\[(.+)\\]$/', $part, $m)) {
|
||||
$result[] = 'in:' . $m[1];
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^greater_than_equal_to\\[(.+)\\]$/', $part, $m)) {
|
||||
$result[] = 'gte:' . $m[1];
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^less_than_equal_to\\[(.+)\\]$/', $part, $m)) {
|
||||
$result[] = 'lte:' . $m[1];
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^valid_date\\[(.+)\\]$/', $part, $m)) {
|
||||
$result[] = 'date_format:' . $m[1];
|
||||
continue;
|
||||
}
|
||||
if ($part === 'valid_email') {
|
||||
$result[] = 'email';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'permit_empty') {
|
||||
$result[] = 'nullable';
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^is_unique\\[([^\\.]+)\\.([^\\]]+)\\]$/', $part, $m)) {
|
||||
$result[] = 'unique:' . $m[1] . ',' . $m[2];
|
||||
continue;
|
||||
}
|
||||
if ($part === 'string') {
|
||||
$result[] = 'string';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'integer') {
|
||||
$result[] = 'integer';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'numeric') {
|
||||
$result[] = 'numeric';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'required') {
|
||||
$result[] = 'required';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'alpha_numeric') {
|
||||
$result[] = 'alpha_num';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'in_array') {
|
||||
$result[] = 'in_array';
|
||||
continue;
|
||||
}
|
||||
if ($part === 'valid_url') {
|
||||
$result[] = 'url';
|
||||
continue;
|
||||
}
|
||||
if (strpos($part, 'max_size') === 0) {
|
||||
$result[] = str_replace('max_size', 'max', $part);
|
||||
continue;
|
||||
}
|
||||
$result[] = $part;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function paginate($source, int $page = 1, int $perPage = 20): array
|
||||
{
|
||||
$page = max(1, $page);
|
||||
$perPage = max(1, $perPage);
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
if ($source instanceof EloquentBuilder || $source instanceof \Illuminate\Database\Query\Builder) {
|
||||
$total = $source->toBase()->getCountForPagination();
|
||||
$items = $source->offset($offset)->limit($perPage)->get()->toArray();
|
||||
} elseif (is_array($source)) {
|
||||
$total = count($source);
|
||||
$items = array_slice($source, $offset, $perPage);
|
||||
} else {
|
||||
return [
|
||||
'data' => [],
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total' => 0,
|
||||
'total_pages' => 0,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => array_values($items),
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total' => $total,
|
||||
'total_pages' => (int) ceil($total / $perPage),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getCurrentUserId(): ?int
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
return $userId > 0 ? $userId : null;
|
||||
}
|
||||
|
||||
protected function getCurrentUser(): ?object
|
||||
{
|
||||
$userId = $this->getCurrentUserId();
|
||||
if (!$userId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = app(User::class);
|
||||
$row = $user->find($userId);
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name = trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? ''));
|
||||
if ($name === '') {
|
||||
$name = $row['email'] ?? 'User #' . $userId;
|
||||
}
|
||||
|
||||
try {
|
||||
$roles = DB::table('user_roles ur')
|
||||
->select('LOWER(r.name) AS name')
|
||||
->join('roles r', 'r.id', '=', 'ur.role_id')
|
||||
->where('ur.user_id', $userId)
|
||||
->whereNull('ur.deleted_at')
|
||||
->pluck('name')
|
||||
->map(fn($name) => strtolower((string) $name))
|
||||
->unique()
|
||||
->values()
|
||||
->toArray();
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Unable to load user roles: ' . $e->getMessage());
|
||||
$roles = [];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'id' => (int) $userId,
|
||||
'name' => $name,
|
||||
'email' => $row['email'] ?? null,
|
||||
'roles' => $roles,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Core;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CiRequestAdapter
|
||||
{
|
||||
public function __construct(protected Request $request)
|
||||
{
|
||||
}
|
||||
|
||||
public function getGet(string $key = null, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->request->query->all();
|
||||
}
|
||||
return $this->request->query->get($key, $default);
|
||||
}
|
||||
|
||||
public function getPost(string $key = null, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->request->request->all();
|
||||
}
|
||||
return $this->request->request->get($key, $default);
|
||||
}
|
||||
|
||||
public function getJSON(bool $assoc = false)
|
||||
{
|
||||
$content = $this->request->getContent();
|
||||
if ($content === '') {
|
||||
return $assoc ? [] : null;
|
||||
}
|
||||
return json_decode($content, $assoc);
|
||||
}
|
||||
|
||||
public function getVar(string $key, $default = null)
|
||||
{
|
||||
return $this->request->input($key, $default);
|
||||
}
|
||||
|
||||
public function getHeader(string $key)
|
||||
{
|
||||
return $this->request->headers->get($key);
|
||||
}
|
||||
|
||||
public function getHeaderLine(string $key)
|
||||
{
|
||||
return $this->request->header($key);
|
||||
}
|
||||
|
||||
public function getFile(string $key)
|
||||
{
|
||||
return $this->request->file($key);
|
||||
}
|
||||
|
||||
public function getRawInput(): string
|
||||
{
|
||||
return $this->request->getContent();
|
||||
}
|
||||
|
||||
public function all(): array
|
||||
{
|
||||
return array_merge(
|
||||
$this->request->query->all(),
|
||||
$this->request->request->all(),
|
||||
$this->request->json()->all()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Discounts;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Discounts\ApplyDiscountVoucherRequest;
|
||||
use App\Http\Requests\Discounts\StoreDiscountVoucherRequest;
|
||||
use App\Http\Requests\Discounts\UpdateDiscountVoucherRequest;
|
||||
@@ -50,12 +50,17 @@ class DiscountController extends BaseApiController
|
||||
|
||||
public function apply(ApplyDiscountVoucherRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->applyService->applyVoucher(
|
||||
(int) $payload['voucher_id'],
|
||||
$payload['parent_ids'],
|
||||
(bool) ($payload['allow_additional'] ?? false),
|
||||
(int) (auth()->id() ?? 0)
|
||||
$guard
|
||||
);
|
||||
|
||||
return response()->json($result, $result['ok'] ? 200 : 422);
|
||||
@@ -104,4 +109,17 @@ class DiscountController extends BaseApiController
|
||||
'ok' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Documentation;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Docs\ApiDocsService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Authenticated API explorer bootstrap + public read-only variant.
|
||||
*/
|
||||
class ApiDocsAdminController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private ApiDocsService $apiDocs,
|
||||
) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->json(
|
||||
$this->apiDocs->bootstrap(Auth::user(), false),
|
||||
);
|
||||
}
|
||||
|
||||
public function public(): JsonResponse
|
||||
{
|
||||
return response()->json(
|
||||
$this->apiDocs->bootstrap(null, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Documentation;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Docs\DocsCatalogService;
|
||||
use App\Services\Docs\OpenApiRouteExporter;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* Docs hub + multi-spec Swagger catalog (JSON for SPA).
|
||||
*/
|
||||
class DocsCatalogController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private DocsCatalogService $catalog,
|
||||
) {}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
return redirect()->to((string) config('docs.client_url', url('/docs')));
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $this->catalog->indexPayload(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function ui(): View
|
||||
{
|
||||
return view('docs.swagger');
|
||||
}
|
||||
|
||||
public function swagger(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $this->catalog->swaggerSpecsPayload(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merged OpenAPI spec (static openapi.json + live route merge).
|
||||
*/
|
||||
public function swaggerMergedJson(): JsonResponse
|
||||
{
|
||||
$path = resource_path('docs/openapi.json');
|
||||
abort_unless(is_file($path), 404);
|
||||
|
||||
$spec = app(OpenApiRouteExporter::class)->exportFromFile($path);
|
||||
|
||||
return response()->json($spec, 200, [
|
||||
'Content-Type' => 'application/json',
|
||||
'Cache-Control' => 'no-store, max-age=0',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Email;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Services\BroadcastEmail\BroadcastEmailComposerService;
|
||||
use App\Services\BroadcastEmail\BroadcastEmailDispatchService;
|
||||
use App\Services\BroadcastEmail\BroadcastEmailImageService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Email;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Email\EmailSendRequest;
|
||||
use App\Http\Resources\Email\EmailSenderResource;
|
||||
use App\Services\Email\EmailAttachmentService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Email;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Email\EmailExtractorCompareRequest;
|
||||
use App\Http\Resources\Email\EmailExtractorCompareResource;
|
||||
use App\Http\Resources\Email\EmailExtractorEmailsResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Exams;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Exams\ExamDraftAdminLegacyRequest;
|
||||
use App\Http\Requests\Exams\ExamDraftAdminReviewRequest;
|
||||
use App\Http\Requests\Exams\ExamDraftTeacherStoreRequest;
|
||||
@@ -22,12 +22,12 @@ class ExamDraftController extends BaseApiController
|
||||
|
||||
public function teacherIndex(): JsonResponse
|
||||
{
|
||||
$teacherId = (int) (auth()->id() ?? 0);
|
||||
if ($teacherId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->teacherService->listForTeacher($teacherId);
|
||||
$data = $this->teacherService->listForTeacher($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -43,12 +43,12 @@ class ExamDraftController extends BaseApiController
|
||||
|
||||
public function teacherStore(ExamDraftTeacherStoreRequest $request): JsonResponse
|
||||
{
|
||||
$teacherId = (int) (auth()->id() ?? 0);
|
||||
if ($teacherId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->teacherService->store($teacherId, $request->validated(), $request->file('draft_file'));
|
||||
$result = $this->teacherService->store($guard, $request->validated(), $request->file('draft_file'));
|
||||
if (!$result['ok']) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to save.'], 422);
|
||||
}
|
||||
@@ -79,12 +79,12 @@ class ExamDraftController extends BaseApiController
|
||||
|
||||
public function adminUploadLegacy(ExamDraftAdminLegacyRequest $request): JsonResponse
|
||||
{
|
||||
$adminId = (int) (auth()->id() ?? 0);
|
||||
if ($adminId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->adminService->uploadLegacy($adminId, $request->validated(), $request->file('old_exam_file'));
|
||||
$result = $this->adminService->uploadLegacy($guard, $request->validated(), $request->file('old_exam_file'));
|
||||
if (!$result['ok']) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to save.'], 422);
|
||||
}
|
||||
@@ -97,12 +97,12 @@ class ExamDraftController extends BaseApiController
|
||||
|
||||
public function adminReview(ExamDraftAdminReviewRequest $request): JsonResponse
|
||||
{
|
||||
$adminId = (int) (auth()->id() ?? 0);
|
||||
if ($adminId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->adminService->review($adminId, $request->validated(), $request->file('final_file'));
|
||||
$result = $this->adminService->review($guard, $request->validated(), $request->file('final_file'));
|
||||
if (!$result['ok']) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to save.'], 422);
|
||||
}
|
||||
@@ -112,4 +112,17 @@ class ExamDraftController extends BaseApiController
|
||||
'draft' => new ExamDraftResource($result['draft']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Expenses;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Expenses\StoreExpenseRequest;
|
||||
use App\Http\Requests\Expenses\UpdateExpenseRequest;
|
||||
use App\Http\Requests\Expenses\UpdateExpenseStatusRequest;
|
||||
@@ -77,8 +77,12 @@ class ExpenseController extends BaseApiController
|
||||
|
||||
public function store(StoreExpenseRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$receiptName = null;
|
||||
if ($request->hasFile('receipt')) {
|
||||
@@ -95,10 +99,10 @@ class ExpenseController extends BaseApiController
|
||||
'retailor' => $payload['retailor'] ?? null,
|
||||
'date_of_purchase' => $payload['date_of_purchase'],
|
||||
'purchased_by' => (int) $payload['purchased_by'],
|
||||
'added_by' => $userId,
|
||||
'added_by' => $guard,
|
||||
'status' => $isDonation ? 'approved' : 'pending',
|
||||
'status_reason' => $isDonation ? 'Marked as Donation (non-reimbursable).' : null,
|
||||
'approved_by' => $isDonation ? $userId : null,
|
||||
'approved_by' => $isDonation ? $guard : null,
|
||||
'school_year' => $payload['school_year'] ?? null,
|
||||
'semester' => $payload['semester'] ?? null,
|
||||
]);
|
||||
@@ -111,13 +115,17 @@ class ExpenseController extends BaseApiController
|
||||
|
||||
public function update(UpdateExpenseRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$expense = Expense::query()->find($id);
|
||||
if (!$expense) {
|
||||
return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$receiptName = $expense->receipt_path;
|
||||
if ($request->hasFile('receipt')) {
|
||||
@@ -138,13 +146,13 @@ class ExpenseController extends BaseApiController
|
||||
'date_of_purchase' => $payload['date_of_purchase'],
|
||||
'purchased_by' => (int) $payload['purchased_by'],
|
||||
'receipt_path' => $receiptName,
|
||||
'updated_by' => $userId,
|
||||
'updated_by' => $guard,
|
||||
];
|
||||
|
||||
if ($isDonation) {
|
||||
$updateData['status'] = 'approved';
|
||||
$updateData['status_reason'] = 'Marked as Donation (non-reimbursable).';
|
||||
$updateData['approved_by'] = $userId ?: null;
|
||||
$updateData['approved_by'] = $guard ?: null;
|
||||
$updateData['reimbursement_id'] = null;
|
||||
} elseif (($expense->category ?? '') === 'Donation') {
|
||||
$updateData['status_reason'] = null;
|
||||
@@ -162,19 +170,36 @@ class ExpenseController extends BaseApiController
|
||||
|
||||
public function updateStatus(UpdateExpenseStatusRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$expense = Expense::query()->find($id);
|
||||
if (!$expense) {
|
||||
return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$updated = $this->statusService->updateStatus($expense, $payload['status'], $payload['reason'] ?? '', $userId);
|
||||
$updated = $this->statusService->updateStatus($expense, $payload['status'], $payload['reason'] ?? '', $guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'expense' => new ExpenseResource($updated->toArray()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\ExtraCharges;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\ExtraCharges\StoreExtraChargeRequest;
|
||||
use App\Http\Requests\ExtraCharges\UpdateExtraChargeRequest;
|
||||
use App\Http\Resources\ExtraCharges\ExtraChargeInvoiceOptionResource;
|
||||
@@ -87,8 +87,13 @@ class ExtraChargesController extends BaseApiController
|
||||
|
||||
public function store(StoreExtraChargeRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$payload['created_by'] = (int) (auth()->id() ?? 0);
|
||||
$payload['created_by'] = $userId;
|
||||
|
||||
$result = $this->chargeService->createCharge($payload);
|
||||
|
||||
@@ -102,8 +107,13 @@ class ExtraChargesController extends BaseApiController
|
||||
return response()->json(['ok' => false, 'error' => 'Charge not found'], 404);
|
||||
}
|
||||
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$payload['updated_by'] = (int) (auth()->id() ?? 0);
|
||||
$payload['updated_by'] = $userId;
|
||||
|
||||
$ok = $this->chargeService->updateCharge($charge, $payload);
|
||||
|
||||
@@ -140,4 +150,17 @@ class ExtraChargesController extends BaseApiController
|
||||
'ok' => $ok,
|
||||
], $ok ? 200 : 422);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Family;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Families\FamilyAdminCardRequest;
|
||||
use App\Http\Requests\Families\FamilyAdminIndexRequest;
|
||||
use App\Http\Requests\Families\FamilyAdminSearchRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Family;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Families\FamiliesByStudentRequest;
|
||||
use App\Http\Requests\Families\FamilyAttachSecondByEmailRequest;
|
||||
use App\Http\Requests\Families\FamilyAttachSecondByUserRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Finance\FeeRefundRequest;
|
||||
use App\Http\Requests\Finance\FeeTuitionTotalRequest;
|
||||
use App\Http\Resources\Fees\FeeRefundResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Finance\FinancialReportRequest;
|
||||
use App\Http\Requests\Finance\FinancialSummaryRequest;
|
||||
use App\Http\Requests\Finance\FinancialUnpaidParentsRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Invoices\InvoiceManagementRequest;
|
||||
use App\Http\Requests\Invoices\InvoiceParentRequest;
|
||||
use App\Http\Requests\Invoices\InvoiceStatusRequest;
|
||||
@@ -88,9 +88,9 @@ class InvoiceController extends BaseApiController
|
||||
|
||||
public function parentPayment(InvoiceParentRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$parentId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($parentId instanceof JsonResponse) {
|
||||
return $parentId;
|
||||
}
|
||||
|
||||
$schoolYear = $request->validated()['school_year'] ?? null;
|
||||
@@ -136,4 +136,17 @@ class InvoiceController extends BaseApiController
|
||||
echo $pdfBytes;
|
||||
}, 'invoice_' . $invoiceId . '.pdf', ['Content-Type' => 'application/pdf']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Payments\PaymentByParentRequest;
|
||||
use App\Http\Resources\Payments\PaymentResource;
|
||||
use App\Services\Payments\PaymentBalanceService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Payments\PaymentEventChargesListRequest;
|
||||
use App\Services\Payments\PaymentEventChargesService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -26,6 +26,11 @@ class PaymentEventChargesController extends BaseApiController
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'parent_id' => ['required', 'integer', 'min:1'],
|
||||
@@ -47,9 +52,8 @@ class PaymentEventChargesController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$count = $this->service->addCharges($payload, $userId);
|
||||
$count = $this->service->addCharges($payload, $guard);
|
||||
if ($count === 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'No student selected.'], 422);
|
||||
}
|
||||
@@ -64,4 +68,17 @@ class PaymentEventChargesController extends BaseApiController
|
||||
|
||||
return response()->json(['ok' => true, 'students' => $students]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Payments\PaymentManualEditRequest;
|
||||
use App\Http\Requests\Payments\PaymentManualUpdateRequest;
|
||||
use App\Services\Payments\PaymentManualService;
|
||||
@@ -63,6 +63,11 @@ class PaymentManualController extends BaseApiController
|
||||
|
||||
public function record(PaymentManualUpdateRequest $request, int $invoiceId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
|
||||
$result = $this->service->recordPayment(
|
||||
@@ -75,7 +80,7 @@ class PaymentManualController extends BaseApiController
|
||||
$request->file('payment_file'),
|
||||
$payload['school_year'] ?? null,
|
||||
$payload['semester'] ?? null,
|
||||
(int) (auth()->id() ?? 0)
|
||||
$guard
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true] + $result);
|
||||
@@ -83,6 +88,11 @@ class PaymentManualController extends BaseApiController
|
||||
|
||||
public function edit(PaymentManualEditRequest $request, int $paymentId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
|
||||
$this->service->editPayment(
|
||||
@@ -91,7 +101,7 @@ class PaymentManualController extends BaseApiController
|
||||
(string) $payload['payment_method'],
|
||||
$payload['check_number'] ?? null,
|
||||
$request->file('payment_file'),
|
||||
(int) (auth()->id() ?? 0)
|
||||
$guard
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
@@ -102,4 +112,17 @@ class PaymentManualController extends BaseApiController
|
||||
$mode = (string) ($request->query('mode') ?? 'download');
|
||||
return $this->service->serveCheckFile($filename, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Payments\PaymentNotificationListRequest;
|
||||
use App\Http\Requests\Payments\PaymentNotificationSendRequest;
|
||||
use App\Http\Resources\Payments\PaymentNotificationLogResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Resources\Payments\PaymentTransactionResource;
|
||||
use App\Services\Payments\PaymentTransactionService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Payments\PaypalExecuteRequest;
|
||||
use App\Services\Payments\PaypalPaymentService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Payments\PaypalTransactionsListRequest;
|
||||
use App\Http\Resources\Payments\PaypalTransactionResource;
|
||||
use App\Services\Payments\PaypalTransactionsService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\PurchaseOrders\PurchaseOrderIndexRequest;
|
||||
use App\Http\Resources\PurchaseOrders\PurchaseOrderItemResource;
|
||||
use App\Http\Resources\PurchaseOrders\PurchaseOrderResource;
|
||||
@@ -99,6 +99,10 @@ class PurchaseOrderController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
if (auth()->user() === null) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
try {
|
||||
$po = $this->createService->create($payload);
|
||||
} catch (RuntimeException $e) {
|
||||
@@ -137,7 +141,11 @@ class PurchaseOrderController extends BaseApiController
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$issuedBy = $user ? (string) ($user->email ?? $user->username ?? $user->id) : 'system';
|
||||
if ($user === null) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
$issuedBy = (string) ($user->email ?? $user->username ?? $user->id);
|
||||
|
||||
try {
|
||||
$result = $this->receiveService->receive($id, $payload['items'], $issuedBy);
|
||||
@@ -156,6 +164,10 @@ class PurchaseOrderController extends BaseApiController
|
||||
|
||||
public function cancel(int $id): JsonResponse
|
||||
{
|
||||
if (auth()->user() === null) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
$po = PurchaseOrder::query()->find($id);
|
||||
if (!$po) {
|
||||
return response()->json(['ok' => false, 'message' => 'Purchase order not found.'], 404);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Refunds\RefundDecisionRequest;
|
||||
use App\Http\Requests\Refunds\RefundIndexRequest;
|
||||
use App\Http\Requests\Refunds\RefundPaymentRequest;
|
||||
@@ -60,11 +60,15 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function store(RefundStoreRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
|
||||
try {
|
||||
$result = $this->requestService->requestRefund($payload, $actorId);
|
||||
$result = $this->requestService->requestRefund($payload, $guard);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Refund request failed.', ['error' => $e->getMessage()]);
|
||||
return response()->json(['ok' => false, 'message' => 'Failed to submit refund request.'], 500);
|
||||
@@ -88,14 +92,18 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function update(RefundDecisionRequest $request, int $refundId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$result = $this->decisionService->updateDecision(
|
||||
$refundId,
|
||||
(string) $payload['status'],
|
||||
(string) $payload['reason'],
|
||||
$actorId
|
||||
$guard
|
||||
);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
@@ -107,8 +115,12 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function destroy(int $refundId): JsonResponse
|
||||
{
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->decisionService->cancel($refundId, $actorId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->decisionService->cancel($refundId, $guard);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to cancel refund.'], 404);
|
||||
@@ -119,8 +131,12 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function approve(int $refundId): JsonResponse
|
||||
{
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->decisionService->approve($refundId, $actorId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->decisionService->approve($refundId, $guard);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Approve failed.'], 422);
|
||||
@@ -131,9 +147,13 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function reject(RefundRejectRequest $request, int $refundId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->decisionService->reject($refundId, (string) $payload['reason'], $actorId);
|
||||
$result = $this->decisionService->reject($refundId, (string) $payload['reason'], $guard);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Reject failed.'], 422);
|
||||
@@ -144,11 +164,15 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function recordPayment(RefundPaymentRequest $request, int $refundId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$payload['check_file'] = $request->file('check_file');
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$result = $this->payoutService->recordPayment($refundId, $payload, $actorId);
|
||||
$result = $this->payoutService->recordPayment($refundId, $payload, $guard);
|
||||
if (empty($result['ok'])) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to update payment.'], 422);
|
||||
}
|
||||
@@ -158,10 +182,14 @@ class RefundController extends BaseApiController
|
||||
|
||||
public function recalculateOverpayments(RefundRecalculateRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->overpaymentService->recalculate(true, $payload['invoice_number'] ?? null, $actorId);
|
||||
$payload = $request->validated();
|
||||
|
||||
$result = $this->overpaymentService->recalculate(true, $payload['invoice_number'] ?? null, $guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -183,4 +211,17 @@ class RefundController extends BaseApiController
|
||||
'summary' => $summary,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Finance;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Files\FileNameRequest;
|
||||
use App\Http\Requests\Reimbursements\ReimbursementBatchAdminFileRequest;
|
||||
use App\Http\Requests\Reimbursements\ReimbursementBatchAssignmentRequest;
|
||||
@@ -68,6 +68,11 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function markDonation(Request $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'expense_id' => ['required', 'integer', 'min:1'],
|
||||
@@ -81,10 +86,9 @@ class ReimbursementController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
try {
|
||||
$this->donationService->markDonation((int) $payload['expense_id'], $userId);
|
||||
$this->donationService->markDonation((int) $payload['expense_id'], $guard);
|
||||
} catch (RuntimeException $e) {
|
||||
$message = $e->getMessage();
|
||||
$status = str_contains($message, 'not found') ? 404 : (str_contains($message, 'already') ? 409 : 422);
|
||||
@@ -98,6 +102,11 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function createBatch(Request $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'title' => ['nullable', 'string', 'max:255'],
|
||||
@@ -111,11 +120,10 @@ class ReimbursementController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
$schoolYear = $this->context->getSchoolYear();
|
||||
$semester = $this->context->getSemester();
|
||||
|
||||
$batch = $this->batchService->createBatch($payload['title'] ?? null, $userId, $schoolYear, $semester);
|
||||
$batch = $this->batchService->createBatch($payload['title'] ?? null, $guard, $schoolYear, $semester);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -158,13 +166,17 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function lockBatch(ReimbursementBatchLockRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
try {
|
||||
$this->batchService->lockBatch(
|
||||
(int) $payload['batch_id'],
|
||||
$userId,
|
||||
$guard,
|
||||
$this->context->getSchoolYear(),
|
||||
$this->context->getSemester()
|
||||
);
|
||||
@@ -181,6 +193,11 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function uploadBatchAdminFile(ReimbursementBatchAdminFileRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$batchId = (int) $payload['batch_id'];
|
||||
$adminId = (int) $payload['admin_id'];
|
||||
@@ -194,7 +211,7 @@ class ReimbursementController extends BaseApiController
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $this->fileService->storeAdminFile($batchId, $adminId, $request->file('check_file'), (int) (auth()->id() ?? 0));
|
||||
$file = $this->fileService->storeAdminFile($batchId, $adminId, $request->file('check_file'), $guard);
|
||||
} catch (\Throwable $e) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unable to store the uploaded file.'], 500);
|
||||
}
|
||||
@@ -312,6 +329,11 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'amount' => ['required', 'numeric', 'gt:0'],
|
||||
@@ -333,7 +355,6 @@ class ReimbursementController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
$receiptName = null;
|
||||
|
||||
if ($request->hasFile('receipt')) {
|
||||
@@ -343,7 +364,7 @@ class ReimbursementController extends BaseApiController
|
||||
try {
|
||||
$reimb = $this->crudService->store(
|
||||
$payload,
|
||||
$userId,
|
||||
$guard,
|
||||
$this->context->getSchoolYear(),
|
||||
$this->context->getSemester(),
|
||||
$receiptName
|
||||
@@ -363,8 +384,12 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function process(ReimbursementProcessRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
$receiptName = null;
|
||||
|
||||
if ($request->hasFile('receipt')) {
|
||||
@@ -374,7 +399,7 @@ class ReimbursementController extends BaseApiController
|
||||
try {
|
||||
$reimb = $this->crudService->process(
|
||||
$payload,
|
||||
$userId,
|
||||
$guard,
|
||||
$this->context->getSchoolYear(),
|
||||
$this->context->getSemester(),
|
||||
$receiptName
|
||||
@@ -404,6 +429,11 @@ class ReimbursementController extends BaseApiController
|
||||
|
||||
public function update(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$reimb = Reimbursement::query()->find($id);
|
||||
if (!$reimb) {
|
||||
return response()->json(['ok' => false, 'message' => 'Reimbursement not found.'], 404);
|
||||
@@ -428,7 +458,6 @@ class ReimbursementController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$receiptName = $reimb->receipt_path;
|
||||
if ($request->hasFile('receipt')) {
|
||||
@@ -438,7 +467,7 @@ class ReimbursementController extends BaseApiController
|
||||
$receiptName = null;
|
||||
}
|
||||
|
||||
$updated = $this->crudService->update($reimb, $payload, $userId, $receiptName);
|
||||
$updated = $this->crudService->update($reimb, $payload, $guard, $receiptName);
|
||||
$data = $updated->toArray();
|
||||
$data['receipt_url'] = $this->fileService->receiptUrl($updated->receipt_path ?? null);
|
||||
|
||||
@@ -447,4 +476,17 @@ class ReimbursementController extends BaseApiController
|
||||
'reimbursement' => new ReimbursementResource($data),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Frontend;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Resources\Frontend\FrontendPageResource;
|
||||
use App\Http\Resources\Frontend\FrontendUserResource;
|
||||
use App\Services\Frontend\FrontendPageService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Frontend;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Resources\Frontend\ProfileIconResource;
|
||||
use App\Services\Frontend\ProfileIconService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -17,15 +17,28 @@ class InfoIconController extends BaseApiController
|
||||
|
||||
public function profileIcon(): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $this->service->buildForUser($userId);
|
||||
$payload = $this->service->buildForUser($guard);
|
||||
|
||||
return $this->success([
|
||||
'profile' => new ProfileIconResource($payload),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Frontend;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Frontend\LandingTeacherRequest;
|
||||
use App\Http\Resources\Frontend\LandingPageResource;
|
||||
use App\Services\Frontend\LandingPageService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class LandingPageController extends BaseApiController
|
||||
{
|
||||
@@ -17,8 +18,13 @@ class LandingPageController extends BaseApiController
|
||||
|
||||
public function index(LandingTeacherRequest $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$payload = $this->service->dashboardForUser(
|
||||
$request->user(),
|
||||
$user,
|
||||
$request->validated()['class_section_id'] ?? null
|
||||
);
|
||||
|
||||
@@ -29,8 +35,13 @@ class LandingPageController extends BaseApiController
|
||||
|
||||
public function teacher(LandingTeacherRequest $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$payload = $this->service->teacher(
|
||||
$request->user(),
|
||||
$user,
|
||||
$request->validated()['class_section_id'] ?? null
|
||||
);
|
||||
|
||||
@@ -41,7 +52,12 @@ class LandingPageController extends BaseApiController
|
||||
|
||||
public function parent(): JsonResponse
|
||||
{
|
||||
$payload = $this->service->parent(auth()->user());
|
||||
$user = auth()->user();
|
||||
if (!$user) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$payload = $this->service->parent($user);
|
||||
|
||||
return $this->success([
|
||||
'landing' => new LandingPageResource($payload),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Frontend;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Frontend\ContactSubmitRequest;
|
||||
use App\Http\Resources\Frontend\ContactSubmissionResource;
|
||||
use App\Http\Resources\Frontend\PageContentResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Grading;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Grading\BelowSixtyEmailRequest;
|
||||
use App\Http\Requests\Grading\BelowSixtyMeetingRequest;
|
||||
use App\Http\Requests\Grading\BelowSixtyMeetingSaveRequest;
|
||||
@@ -79,20 +79,30 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function update(GradingScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->scoreService->update($payload, (int) (auth()->id() ?? 0));
|
||||
$this->scoreService->update($payload, $userId);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
public function toggleLock(GradingLockRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$locked = $this->lockService->toggle(
|
||||
(int) $payload['class_section_id'],
|
||||
(string) $payload['semester'],
|
||||
(string) $payload['school_year'],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'locked' => $locked]);
|
||||
@@ -100,11 +110,16 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function lockAll(GradingLockAllRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->lockService->lockAll(
|
||||
(string) $payload['semester'],
|
||||
(string) $payload['school_year'],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'locked_count' => $count]);
|
||||
@@ -137,12 +152,17 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function updatePlacementLevel(PlacementLevelRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->placementService->updatePlacementLevel(
|
||||
(int) $payload['student_id'],
|
||||
(string) $payload['school_year'],
|
||||
$payload['placement_level'] ?? null,
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
@@ -150,12 +170,17 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function updatePlacementLevels(PlacementLevelsRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->placementService->updatePlacementLevels(
|
||||
(int) $payload['class_section_id'],
|
||||
(string) $payload['school_year'],
|
||||
$payload['placement_level'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
@@ -163,12 +188,17 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function createPlacementBatch(PlacementBatchRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$batchId = $this->placementService->createPlacementBatch(
|
||||
(string) $payload['school_year'],
|
||||
(string) $payload['placement_test'],
|
||||
$payload['placement_level'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'batch_id' => $batchId]);
|
||||
@@ -183,12 +213,17 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function updatePlacementBatch(PlacementBatchUpdateRequest $request, int $batchId): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->placementService->updatePlacementBatch(
|
||||
$batchId,
|
||||
(string) $payload['school_year'],
|
||||
$payload['placement_level'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
@@ -246,6 +281,11 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function updateBelowSixtyStatus(BelowSixtyStatusRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->belowSixtyService->updateStatus(
|
||||
(int) $payload['student_id'],
|
||||
@@ -253,7 +293,7 @@ class GradingController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
(string) $payload['status'],
|
||||
(string) ($payload['note'] ?? ''),
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
@@ -273,9 +313,27 @@ class GradingController extends BaseApiController
|
||||
|
||||
public function saveBelowSixtyMeeting(BelowSixtyMeetingSaveRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->belowSixtyService->saveMeeting($payload, (int) (auth()->id() ?? 0));
|
||||
$this->belowSixtyService->saveMeeting($payload, $userId);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Grading;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Grading\HomeworkTrackingRequest;
|
||||
use App\Http\Resources\Grading\HomeworkTrackingTeacherResource;
|
||||
use App\Services\Grading\HomeworkTrackingService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Incidents;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Incidents\IncidentCancelRequest;
|
||||
use App\Http\Requests\Incidents\IncidentCloseRequest;
|
||||
use App\Http\Requests\Incidents\IncidentListRequest;
|
||||
@@ -86,6 +86,11 @@ class IncidentController extends BaseApiController
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'student_id' => ['required', 'integer', 'min:1'],
|
||||
@@ -104,7 +109,7 @@ class IncidentController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
$result = $this->currentService->addIncident($payload, (int) (auth()->id() ?? 0));
|
||||
$result = $this->currentService->addIncident($payload, $guard);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to add incident.'], 422);
|
||||
@@ -129,6 +134,11 @@ class IncidentController extends BaseApiController
|
||||
|
||||
public function close(Request $request, int $incidentId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'state_description' => ['required', 'string', 'max:2000'],
|
||||
@@ -147,7 +157,7 @@ class IncidentController extends BaseApiController
|
||||
$incidentId,
|
||||
(string) $payload['state_description'],
|
||||
$payload['action_taken'] ?? null,
|
||||
(int) (auth()->id() ?? 0)
|
||||
$guard
|
||||
);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
@@ -162,12 +172,17 @@ class IncidentController extends BaseApiController
|
||||
|
||||
public function cancel(IncidentCancelRequest $request, int $incidentId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->currentService->cancelIncident(
|
||||
$incidentId,
|
||||
$payload['state_description'] ?? null,
|
||||
$payload['action_taken'] ?? null,
|
||||
(int) (auth()->id() ?? 0)
|
||||
$guard
|
||||
);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
@@ -179,4 +194,17 @@ class IncidentController extends BaseApiController
|
||||
'incident_id' => $result['incident_id'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Inventory;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Inventory\InventoryCategoryIndexRequest;
|
||||
use App\Http\Requests\Inventory\InventoryCategoryStoreRequest;
|
||||
use App\Http\Requests\Inventory\InventoryCategoryUpdateRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Inventory;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Inventory\InventoryAdjustRequest;
|
||||
use App\Http\Requests\Inventory\InventoryAuditRequest;
|
||||
use App\Http\Requests\Inventory\InventoryItemIndexRequest;
|
||||
@@ -57,7 +57,12 @@ class InventoryController extends BaseApiController
|
||||
|
||||
public function store(InventoryItemStoreRequest $request): JsonResponse
|
||||
{
|
||||
$result = $this->items->create($request->validated(), (int) auth()->id());
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$result = $this->items->create($request->validated(), $actor);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Failed to create item.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
@@ -67,7 +72,12 @@ class InventoryController extends BaseApiController
|
||||
|
||||
public function update(InventoryItemUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$result = $this->items->update($id, $request->validated(), (int) auth()->id());
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$result = $this->items->update($id, $request->validated(), $actor);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Failed to update item.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
@@ -87,7 +97,12 @@ class InventoryController extends BaseApiController
|
||||
|
||||
public function audit(InventoryAuditRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$result = $this->items->auditClassroom($id, $request->validated(), (int) auth()->id());
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$result = $this->items->auditClassroom($id, $request->validated(), $actor);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Failed to audit item.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
@@ -97,7 +112,12 @@ class InventoryController extends BaseApiController
|
||||
|
||||
public function adjust(InventoryAdjustRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$result = $this->items->adjustStock($id, $request->validated(), (int) auth()->id());
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$result = $this->items->adjustStock($id, $request->validated(), $actor);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Failed to adjust stock.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
@@ -122,9 +142,14 @@ class InventoryController extends BaseApiController
|
||||
|
||||
public function teacherDistribution(InventoryTeacherDistributionRequest $request): JsonResponse
|
||||
{
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->distribution->formData(
|
||||
(int) auth()->id(),
|
||||
$actor,
|
||||
$payload['class_section_id'] ?? null,
|
||||
$payload['item_id'] ?? null
|
||||
);
|
||||
@@ -138,8 +163,13 @@ class InventoryController extends BaseApiController
|
||||
|
||||
public function teacherDistributionStore(InventoryTeacherDistributionStoreRequest $request): JsonResponse
|
||||
{
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->distribution->distribute((int) auth()->id(), $request->validated());
|
||||
$result = $this->distribution->distribute($actor, $request->validated());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Inventory distribution failed: ' . $e->getMessage());
|
||||
return $this->error('Unable to distribute inventory.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
@@ -151,4 +181,17 @@ class InventoryController extends BaseApiController
|
||||
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Inventory;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Inventory\InventoryMovementBulkDeleteRequest;
|
||||
use App\Http\Requests\Inventory\InventoryMovementIndexRequest;
|
||||
use App\Http\Requests\Inventory\InventoryMovementStoreRequest;
|
||||
@@ -30,7 +30,12 @@ class InventoryMovementController extends BaseApiController
|
||||
|
||||
public function store(InventoryMovementStoreRequest $request): JsonResponse
|
||||
{
|
||||
$result = $this->movements->create($request->validated(), (int) auth()->id());
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$result = $this->movements->create($request->validated(), $actor);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Failed to create movement.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
@@ -67,4 +72,17 @@ class InventoryMovementController extends BaseApiController
|
||||
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Inventory;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Inventory\SupplierIndexRequest;
|
||||
use App\Http\Requests\Inventory\SupplierStoreRequest;
|
||||
use App\Http\Requests\Inventory\SupplierUpdateRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Inventory;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Inventory\SupplyCategoryStoreRequest;
|
||||
use App\Http\Requests\Inventory\SupplyCategoryUpdateRequest;
|
||||
use App\Http\Resources\Inventory\SupplyCategoryResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Messaging;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Messaging\MessageIndexRequest;
|
||||
use App\Http\Requests\Messaging\MessageSendRequest;
|
||||
use App\Http\Requests\Messaging\MessageUpdateRequest;
|
||||
@@ -29,9 +29,9 @@ class MessagesController extends BaseApiController
|
||||
|
||||
public function index(MessageIndexRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$filters = $request->validated();
|
||||
@@ -40,8 +40,8 @@ class MessagesController extends BaseApiController
|
||||
|
||||
$this->authorize('viewAny', Message::class);
|
||||
|
||||
$role = $this->queryService->getUserRoleName($userId);
|
||||
$messages = $this->queryService->inbox($userId, $filters, $page, $perPage);
|
||||
$role = $this->queryService->getUserRoleName($guard);
|
||||
$messages = $this->queryService->inbox($guard, $filters, $page, $perPage);
|
||||
$collection = new MessageCollection($messages);
|
||||
$meta = $collection->with($request)['meta'] ?? null;
|
||||
|
||||
@@ -94,15 +94,15 @@ class MessagesController extends BaseApiController
|
||||
|
||||
public function store(MessageSendRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$this->authorize('create', Message::class);
|
||||
|
||||
try {
|
||||
$message = $this->commandService->create($userId, $request->validated(), $request->file('attachment'));
|
||||
$message = $this->commandService->create($guard, $request->validated(), $request->file('attachment'));
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Message send failed: ' . $e->getMessage());
|
||||
return $this->error($e->getMessage(), Response::HTTP_BAD_REQUEST);
|
||||
@@ -115,12 +115,12 @@ class MessagesController extends BaseApiController
|
||||
|
||||
public function receive(): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$messages = $this->queryService->receivedAndMarkRead($userId);
|
||||
$messages = $this->queryService->receivedAndMarkRead($guard);
|
||||
|
||||
return $this->success([
|
||||
'messages' => (new MessageCollection(collect($messages)))->toArray(request()),
|
||||
@@ -193,9 +193,9 @@ class MessagesController extends BaseApiController
|
||||
|
||||
private function listMessages(MessageIndexRequest $request, string $bucket): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$filters = $request->validated();
|
||||
@@ -205,10 +205,10 @@ class MessagesController extends BaseApiController
|
||||
$this->authorize('viewAny', Message::class);
|
||||
|
||||
$paginator = match ($bucket) {
|
||||
'sent' => $this->queryService->sent($userId, $filters, $page, $perPage),
|
||||
'drafts' => $this->queryService->drafts($userId, $filters, $page, $perPage),
|
||||
'trash' => $this->queryService->trash($userId, $filters, $page, $perPage),
|
||||
default => $this->queryService->inbox($userId, $filters, $page, $perPage),
|
||||
'sent' => $this->queryService->sent($guard, $filters, $page, $perPage),
|
||||
'drafts' => $this->queryService->drafts($guard, $filters, $page, $perPage),
|
||||
'trash' => $this->queryService->trash($guard, $filters, $page, $perPage),
|
||||
default => $this->queryService->inbox($guard, $filters, $page, $perPage),
|
||||
};
|
||||
|
||||
$collection = new MessageCollection($paginator);
|
||||
@@ -219,4 +219,17 @@ class MessagesController extends BaseApiController
|
||||
'meta' => $meta,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Messaging;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Whatsapp\WhatsappInviteSendRequest;
|
||||
use App\Http\Requests\Whatsapp\WhatsappLinkIndexRequest;
|
||||
use App\Http\Requests\Whatsapp\WhatsappLinkStoreRequest;
|
||||
@@ -132,8 +132,12 @@ class WhatsappController extends BaseApiController
|
||||
|
||||
public function updateMembership(WhatsappMembershipUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
try {
|
||||
$userId = (int) (auth()->id() ?? 0) ?: null;
|
||||
$result = $this->membershipService->updateMembership($request->validated(), $userId);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('WhatsApp membership update failed: ' . $e->getMessage());
|
||||
@@ -153,4 +157,17 @@ class WhatsappController extends BaseApiController
|
||||
'term' => $result['term'] ?? [],
|
||||
], 'Membership saved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Notifications;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Notifications\NotificationActiveRequest;
|
||||
use App\Http\Requests\Notifications\NotificationDeletedRequest;
|
||||
use App\Http\Requests\Notifications\NotificationIndexRequest;
|
||||
@@ -36,13 +36,13 @@ class NotificationController extends BaseApiController
|
||||
|
||||
public function index(NotificationIndexRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->listService->listForUser($userId, $payload);
|
||||
$result = $this->listService->listForUser($guard, $payload);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -53,12 +53,12 @@ class NotificationController extends BaseApiController
|
||||
|
||||
public function show(int $notificationId): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$row = $this->showService->getForUser($userId, $notificationId);
|
||||
$row = $this->showService->getForUser($guard, $notificationId);
|
||||
if (!$row) {
|
||||
return response()->json(['ok' => false, 'message' => 'Notification not found.'], 404);
|
||||
}
|
||||
@@ -71,11 +71,15 @@ class NotificationController extends BaseApiController
|
||||
|
||||
public function store(NotificationSendRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
|
||||
try {
|
||||
$result = $this->sendService->send($payload, $actorId);
|
||||
$result = $this->sendService->send($payload, $guard);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Notification send failed.', ['error' => $e->getMessage()]);
|
||||
return response()->json(['ok' => false, 'message' => 'Failed to send notification.'], 500);
|
||||
@@ -129,12 +133,12 @@ class NotificationController extends BaseApiController
|
||||
|
||||
public function markRead(int $notificationId): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$ok = $this->readService->markRead($userId, $notificationId);
|
||||
$ok = $this->readService->markRead($guard, $notificationId);
|
||||
if (!$ok) {
|
||||
return response()->json(['ok' => false, 'message' => 'Notification not found.'], 404);
|
||||
}
|
||||
@@ -162,4 +166,17 @@ class NotificationController extends BaseApiController
|
||||
'notifications' => $data['notifications'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Parents;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Parents\AuthorizedUsersManagementService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* Public invite confirmation & password setup for authorized users.
|
||||
*/
|
||||
class AuthorizedUserInviteController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private AuthorizedUsersManagementService $svc,
|
||||
) {}
|
||||
|
||||
public function confirm(Request $request): RedirectResponse|JsonResponse
|
||||
{
|
||||
$token = (string) ($request->query('token') ?? '');
|
||||
try {
|
||||
$result = $this->svc->confirmEmailClick($token);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['message' => $e->getMessage()], 400);
|
||||
}
|
||||
|
||||
return response(
|
||||
'<!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="font-family:sans-serif;padding:24px;">'
|
||||
.'<p>'.e($e->getMessage()).'</p></body></html>',
|
||||
400,
|
||||
['Content-Type' => 'text/html; charset=UTF-8'],
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json([
|
||||
'message' => 'Confirmed.',
|
||||
'redirect_url' => $result['redirect_url'],
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->away($result['redirect_url']);
|
||||
}
|
||||
|
||||
public function setPasswordForm(Request $request, int $authorizedUserId): JsonResponse|Response
|
||||
{
|
||||
$token = (string) ($request->query('token') ?? '');
|
||||
$row = $this->svc->findActiveSetupRow($authorizedUserId, $token);
|
||||
if (! $row) {
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['message' => 'Invalid or expired confirmation link.'], 400);
|
||||
}
|
||||
|
||||
return response('Invalid or expired confirmation link.', 400);
|
||||
}
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json([
|
||||
'message' => 'OK',
|
||||
'user_id' => $authorizedUserId,
|
||||
'token' => $token,
|
||||
]);
|
||||
}
|
||||
|
||||
return response(
|
||||
'<!DOCTYPE html><html><head><meta charset="utf-8"><title>Set password</title></head>'
|
||||
.'<body><p>Set your password using the client app or API POST to this URL with JSON body.</p></body></html>',
|
||||
200,
|
||||
['Content-Type' => 'text/html; charset=UTF-8'],
|
||||
);
|
||||
}
|
||||
|
||||
public function savePassword(Request $request, int $authorizedUserId): JsonResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'password' => ['required', 'string', 'min:8', 'regex:/[A-Z]/', 'regex:/[a-z]/', 'regex:/[0-9]/', 'regex:/[\W_]/'],
|
||||
'password_confirm' => ['required', 'same:password'],
|
||||
'user_id' => ['required', 'integer'],
|
||||
'token' => ['required', 'string'],
|
||||
], [
|
||||
'password.regex' => 'Password must include uppercase, lowercase, number, and special character.',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$data = $validator->validated();
|
||||
|
||||
try {
|
||||
$this->svc->setAuthorizedUserPassword(
|
||||
$authorizedUserId,
|
||||
(int) $data['user_id'],
|
||||
(string) $data['token'],
|
||||
(string) $data['password'],
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 400);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Password has been successfully set.']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Parents;
|
||||
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Parents\StoreAuthorizedUserRequest;
|
||||
use App\Http\Requests\Parents\UpdateAuthorizedUserRequest;
|
||||
use App\Models\AuthorizedUser;
|
||||
use App\Services\Parents\AuthorizedUsersManagementService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Parent CRUD for secondary authorized users on their account (JWT parent role).
|
||||
*/
|
||||
class AuthorizedUsersController extends BaseApiController
|
||||
{
|
||||
public function __construct(
|
||||
private AuthorizedUsersManagementService $svc,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$guard = $this->guardJsonOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$rows = AuthorizedUser::query()
|
||||
->where('user_id', $guard)
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
return $this->success($rows);
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$guard = $this->guardJsonOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$resolution = $this->authorizedUserForParent($id, $guard);
|
||||
if ($resolution instanceof JsonResponse) {
|
||||
return $resolution;
|
||||
}
|
||||
|
||||
return $this->success($resolution);
|
||||
}
|
||||
|
||||
public function store(StoreAuthorizedUserRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->guardJsonOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$email = strtolower($request->validated('email'));
|
||||
$result = $this->svc->inviteByEmail($guard, $email);
|
||||
|
||||
$message = 'Authorized user added. A confirmation email has been sent.';
|
||||
if (! $result['created']) {
|
||||
return $this->success(['message' => $message], $message, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
return $this->success(
|
||||
['message' => $message, 'id' => $result['record']->id],
|
||||
$message,
|
||||
Response::HTTP_CREATED
|
||||
);
|
||||
}
|
||||
|
||||
public function update(UpdateAuthorizedUserRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$guard = $this->guardJsonOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$resolution = $this->authorizedUserForParent($id, $guard);
|
||||
if ($resolution instanceof JsonResponse) {
|
||||
return $resolution;
|
||||
}
|
||||
|
||||
/** @var AuthorizedUser $row */
|
||||
$row = $resolution;
|
||||
|
||||
$email = $request->validated('email') ?? null;
|
||||
if (is_string($email) && $email !== '') {
|
||||
$row->email = strtolower($email);
|
||||
}
|
||||
|
||||
$row->save();
|
||||
|
||||
return $this->success(['message' => 'Authorized user information updated.'], 'Authorized user information updated.');
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$guard = $this->guardJsonOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$resolution = $this->authorizedUserForParent($id, $guard);
|
||||
if ($resolution instanceof JsonResponse) {
|
||||
return $resolution;
|
||||
}
|
||||
|
||||
$resolution->delete();
|
||||
|
||||
return $this->success(['message' => 'Authorized user deleted successfully.'], 'Authorized user deleted successfully.');
|
||||
}
|
||||
|
||||
private function guardJsonOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return $this->error('Authentication required.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $parentId;
|
||||
}
|
||||
|
||||
private function authorizedUserForParent(int $id, int $parentId): AuthorizedUser|JsonResponse
|
||||
{
|
||||
$row = AuthorizedUser::query()->find($id);
|
||||
if (! $row) {
|
||||
return $this->error('Authorized user not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ((int) $row->user_id !== $parentId) {
|
||||
return $this->error('You do not have access to this resource.', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Parents;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Parents\ParentAttendanceReportSubmitRequest;
|
||||
use App\Http\Requests\Parents\ParentAttendanceReportListRequest;
|
||||
use App\Http\Requests\Parents\ParentAttendanceReportCheckRequest;
|
||||
@@ -20,12 +20,12 @@ class ParentAttendanceReportController extends BaseApiController
|
||||
|
||||
public function form(): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->reportService->formData($parentId);
|
||||
$data = $this->reportService->formData($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -40,13 +40,13 @@ class ParentAttendanceReportController extends BaseApiController
|
||||
|
||||
public function submit(ParentAttendanceReportSubmitRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->reportService->submit($parentId, $request->validated());
|
||||
$result = $this->reportService->submit($guard, $request->validated());
|
||||
} catch (\RuntimeException $e) {
|
||||
return response()->json(['ok' => false, 'message' => $e->getMessage()], 422);
|
||||
}
|
||||
@@ -62,13 +62,18 @@ class ParentAttendanceReportController extends BaseApiController
|
||||
|
||||
public function list(ParentAttendanceReportListRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$start = $payload['start'] ?? now()->toDateString();
|
||||
$end = $payload['end'] ?? null;
|
||||
$schoolYear = $payload['school_year'] ?? null;
|
||||
$semester = $payload['semester'] ?? null;
|
||||
|
||||
$rows = $this->reportService->listReports($start, $end, $schoolYear, $semester);
|
||||
$rows = $this->reportService->listReports($start, $end, $schoolYear, $semester, $guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -78,8 +83,13 @@ class ParentAttendanceReportController extends BaseApiController
|
||||
|
||||
public function checkExisting(ParentAttendanceReportCheckRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$rows = $this->reportService->checkExisting($request->validated());
|
||||
$rows = $this->reportService->checkExisting($guard, $request->validated());
|
||||
} catch (\RuntimeException $e) {
|
||||
return response()->json(['ok' => false, 'message' => $e->getMessage()], 422);
|
||||
}
|
||||
@@ -92,17 +102,30 @@ class ParentAttendanceReportController extends BaseApiController
|
||||
|
||||
public function update(ParentAttendanceReportUpdateRequest $request, int $reportId): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->reportService->updateReport($parentId, $reportId, $request->validated());
|
||||
$this->reportService->updateReport($guard, $reportId, $request->validated());
|
||||
} catch (\RuntimeException $e) {
|
||||
return response()->json(['ok' => false, 'message' => $e->getMessage()], 422);
|
||||
}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function parentIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $parentId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Parents;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Parents\ParentAttendanceRequest;
|
||||
use App\Http\Requests\Parents\ParentEnrollmentActionRequest;
|
||||
use App\Http\Requests\Parents\ParentEnrollmentRequest;
|
||||
@@ -41,12 +41,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function attendance(ParentAttendanceRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->attendanceService->listAttendance($parentId, $request->validated()['school_year'] ?? null);
|
||||
$data = $this->attendanceService->listAttendance($guard, $request->validated()['school_year'] ?? null);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -58,13 +58,13 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function invoices(ParentInvoiceRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$schoolYear = $request->validated()['school_year'] ?? null;
|
||||
$rows = $this->invoiceService->listInvoices($parentId, $schoolYear);
|
||||
$rows = $this->invoiceService->listInvoices($guard, $schoolYear);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -74,12 +74,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function enrollments(ParentEnrollmentRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->enrollmentService->overview($parentId, $request->validated()['school_year'] ?? null);
|
||||
$data = $this->enrollmentService->overview($guard, $request->validated()['school_year'] ?? null);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -94,14 +94,14 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function updateEnrollments(ParentEnrollmentActionRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->enrollmentService->updateEnrollment(
|
||||
$parentId,
|
||||
$guard,
|
||||
$payload['enroll'] ?? [],
|
||||
$payload['withdraw'] ?? []
|
||||
);
|
||||
@@ -115,12 +115,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function registration(): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->registrationService->overview($parentId);
|
||||
$data = $this->registrationService->overview($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -136,14 +136,14 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function storeRegistration(ParentRegistrationRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->registrationService->register(
|
||||
$parentId,
|
||||
$guard,
|
||||
$payload['students'] ?? [],
|
||||
$payload['emergency_contacts'] ?? []
|
||||
);
|
||||
@@ -156,36 +156,36 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function updateStudent(ParentStudentUpdateRequest $request, int $studentId): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$this->registrationService->updateStudent($parentId, $studentId, $request->validated());
|
||||
$this->registrationService->updateStudent($guard, $studentId, $request->validated());
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
public function deleteStudent(int $studentId): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$this->registrationService->deleteStudent($parentId, $studentId);
|
||||
$this->registrationService->deleteStudent($guard, $studentId);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
public function emergencyContacts(): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$rows = $this->emergencyContactService->list($parentId);
|
||||
$rows = $this->emergencyContactService->list($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -195,12 +195,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function storeEmergencyContact(ParentEmergencyContactRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$contact = $this->emergencyContactService->store($parentId, $request->validated());
|
||||
$contact = $this->emergencyContactService->store($guard, $request->validated());
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -210,12 +210,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function updateEmergencyContact(ParentEmergencyContactRequest $request, int $contactId): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$contact = $this->emergencyContactService->update($parentId, $contactId, $request->validated());
|
||||
$contact = $this->emergencyContactService->update($guard, $contactId, $request->validated());
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -225,12 +225,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function profile(): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$profile = $this->profileService->getProfile($parentId);
|
||||
$profile = $this->profileService->getProfile($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -240,12 +240,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function updateProfile(ParentProfileUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$profile = $this->profileService->updateProfile($parentId, $request->validated());
|
||||
$profile = $this->profileService->updateProfile($guard, $request->validated());
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -255,12 +255,12 @@ class ParentController extends BaseApiController
|
||||
|
||||
public function events(): JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->eventService->overview($parentId);
|
||||
$data = $this->eventService->overview($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -271,14 +271,27 @@ class ParentController extends BaseApiController
|
||||
}
|
||||
|
||||
public function updateParticipation(ParentEventParticipationRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->parentIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$this->eventService->updateParticipation($guard, $request->validated()['participation'] ?? []);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse Authenticated parent user id, or 401 JSON for this controller's legacy `{ ok }` shape.
|
||||
*/
|
||||
private function parentIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$parentId = (int) (auth()->id() ?? 0);
|
||||
if ($parentId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
$this->eventService->updateParticipation($parentId, $request->validated()['participation'] ?? []);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
return $parentId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\PrintRequests;
|
||||
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Models\PrintRequest;
|
||||
use App\Models\User;
|
||||
use App\Services\PrintRequests\PrintRequestsPortalService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class PrintRequestsController extends BaseApiController
|
||||
{
|
||||
public function __construct(
|
||||
private PrintRequestsPortalService $portal,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function teacher(): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $this->success($this->portal->teacherBootstrap($uid));
|
||||
}
|
||||
|
||||
public function admin(): JsonResponse
|
||||
{
|
||||
return $this->success([
|
||||
'print_requests' => $this->portal->adminPrintRequests(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'file' => ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt'],
|
||||
'page_selection' => ['nullable', 'string', 'regex:/^\s*\d+(?:\s*-\s*\d+)?(?:\s*,\s*\d+(?:\s*-\s*\d+)?)*\s*$/'],
|
||||
'num_copies' => ['required', 'integer', 'min:1'],
|
||||
'required_by' => ['required', 'date'],
|
||||
'pickup_method' => ['required', 'string', 'max:255'],
|
||||
'class_id' => ['required', 'integer', 'min:1'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Http\UploadedFile $file */
|
||||
$file = $request->file('file');
|
||||
$model = $this->portal->storeTeacherUpload($validator->validated(), $file, $uid);
|
||||
|
||||
return $this->respondCreated(
|
||||
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
|
||||
'Print request created successfully.'
|
||||
);
|
||||
}
|
||||
|
||||
public function teacherUpdate(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$pr = PrintRequest::query()->find($id);
|
||||
if (! $pr) {
|
||||
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (! $this->portal->teacherOwnsRequest($pr, $uid)) {
|
||||
return $this->error('You are not authorized to edit this request.', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
if (! $this->portal->teacherMayEditOrDelete($pr)) {
|
||||
return $this->error('Cannot edit a request that is already being processed.', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'num_copies' => ['required', 'integer', 'min:1'],
|
||||
'required_by' => ['required', 'date'],
|
||||
'pickup_method' => ['required', 'string', Rule::in(['Self Pickup', 'Delivered to class'])],
|
||||
'page_selection' => ['nullable', 'string', 'regex:/^\s*\d+(?:\s*-\s*\d+)?(?:\s*,\s*\d+(?:\s*-\s*\d+)?)*\s*$/'],
|
||||
];
|
||||
|
||||
if ($request->hasFile('file') && $request->file('file')->isValid()) {
|
||||
$rules['file'] = ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt'];
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
$data = $validator->validated();
|
||||
$newFile = ($request->hasFile('file') && $request->file('file')->isValid())
|
||||
? $request->file('file')
|
||||
: null;
|
||||
|
||||
$model = $this->portal->updateTeacherFields($pr, $data, $newFile);
|
||||
|
||||
return $this->success(
|
||||
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
|
||||
'Print request updated successfully.'
|
||||
);
|
||||
}
|
||||
|
||||
public function adminStatus(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'status' => ['required', 'string', Rule::in(['not_assigned', 'assigned', 'done', 'delivered'])],
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
$pr = PrintRequest::query()->find($id);
|
||||
if (! $pr) {
|
||||
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$newStatus = (string) $validator->validated()['status'];
|
||||
|
||||
try {
|
||||
$model = $this->portal->applyAdminStatus($pr, $newStatus, $uid);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return $this->error($e->getMessage(), Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
return $this->success(
|
||||
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
|
||||
'Status updated successfully.'
|
||||
);
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$pr = PrintRequest::query()->find($id);
|
||||
if (! $pr) {
|
||||
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (! $this->portal->teacherOwnsRequest($pr, $uid)) {
|
||||
return $this->error('You are not authorized to delete this request.', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
if (! $this->portal->teacherMayEditOrDelete($pr)) {
|
||||
return $this->error('Cannot delete a request that is already being processed.', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->portal->deleteTeacherRequest($pr);
|
||||
|
||||
return $this->respondDeleted(null, 'Print request deleted successfully.');
|
||||
}
|
||||
|
||||
public function copy(int $id): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$pr = PrintRequest::query()->find($id);
|
||||
if (! $pr) {
|
||||
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (! $this->portal->teacherOwnsRequest($pr, $uid)) {
|
||||
return $this->error('You are not authorized to copy this request.', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
try {
|
||||
$model = $this->portal->copyFromExisting($pr, $uid);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return $this->error($e->getMessage(), Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
return $this->respondCreated(
|
||||
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
|
||||
'Print request copied successfully.'
|
||||
);
|
||||
}
|
||||
|
||||
public function handCopy(Request $request): JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'num_copies' => ['required', 'integer', 'min:1'],
|
||||
'required_by' => ['required', 'date'],
|
||||
'pickup_method' => ['required', 'string', 'max:255'],
|
||||
'class_id' => ['required', 'integer', 'min:1'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
$model = $this->portal->storeHandCopy($validator->validated(), $uid);
|
||||
|
||||
return $this->respondCreated(
|
||||
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
|
||||
'Copy request submitted. Please hand the original document to the copy center.'
|
||||
);
|
||||
}
|
||||
|
||||
public function download(int $id): BinaryFileResponse|JsonResponse
|
||||
{
|
||||
$uid = $this->getCurrentUserId();
|
||||
if (! $uid) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$pr = PrintRequest::query()->find($id);
|
||||
if (! $pr) {
|
||||
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$isAdmin = $this->userHasPrintAdminRole(Auth::user());
|
||||
if (! $this->portal->authorizeDownload($pr, $uid, $isAdmin)) {
|
||||
return $this->error('Forbidden.', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
$path = $this->portal->absolutePathForDownload($pr);
|
||||
if ($path === null || ! is_readable($path)) {
|
||||
return $this->error('File not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$mime = @mime_content_type($path) ?: 'application/octet-stream';
|
||||
$safe = basename($path);
|
||||
|
||||
return response()->download($path, $safe, [
|
||||
'Content-Type' => $mime,
|
||||
]);
|
||||
}
|
||||
|
||||
private function userHasPrintAdminRole(?User $user): bool
|
||||
{
|
||||
if (! $user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$roles = $user->roles()
|
||||
->pluck('roles.name')
|
||||
->map(fn ($name) => strtolower((string) $name))
|
||||
->toArray();
|
||||
|
||||
foreach (['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'] as $allowed) {
|
||||
if (in_array($allowed, $roles, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Public;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PublicWinners\PublicWinnersPortalService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Published competition winners (public JSON).
|
||||
*/
|
||||
class PublicWinnersController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private PublicWinnersPortalService $winners,
|
||||
) {}
|
||||
|
||||
public function competitionIndex(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => [
|
||||
'competitions' => $this->winners->publishedCompetitions(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function competitionShow(int $id): JsonResponse
|
||||
{
|
||||
$payload = $this->winners->competitionPayload($id);
|
||||
if ($payload === null) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Competition not found.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $payload,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Reports;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Files\FileNameRequest;
|
||||
use App\Http\Resources\Files\FileMetaResource;
|
||||
use App\Services\Files\ExamDraftDownloadNameService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Reports;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Reports\ReportCards\ReportCardAcknowledgementRequest;
|
||||
use App\Http\Requests\Reports\ReportCards\ReportCardCompletenessRequest;
|
||||
use App\Http\Requests\Reports\ReportCards\ReportCardMetaRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Reports;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Reports\SlipLogListRequest;
|
||||
use App\Http\Requests\Reports\SlipPreviewRequest;
|
||||
use App\Http\Requests\Reports\SlipPrintRequest;
|
||||
@@ -20,8 +20,12 @@ class SlipPrinterController extends BaseApiController
|
||||
|
||||
public function print(SlipPrintRequest $request)
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->service->print($request->validated(), $userId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->service->print($request->validated(), $guard);
|
||||
|
||||
if (!$result['ok']) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Print failed.'], 422);
|
||||
@@ -35,8 +39,12 @@ class SlipPrinterController extends BaseApiController
|
||||
|
||||
public function preview(SlipPreviewRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->service->preview($request->validated(), $userId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->service->preview($request->validated(), $guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -47,6 +55,11 @@ class SlipPrinterController extends BaseApiController
|
||||
|
||||
public function logs(SlipLogListRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$rows = $this->service->logs($payload['school_year'] ?? null, $payload['semester'] ?? null);
|
||||
|
||||
@@ -58,8 +71,12 @@ class SlipPrinterController extends BaseApiController
|
||||
|
||||
public function reprint(SlipReprintRequest $request)
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->service->reprint((int) $request->validated()['id'], $userId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->service->reprint((int) $request->validated()['id'], $guard);
|
||||
|
||||
if (!$result['ok']) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Slip not found.'], 404);
|
||||
@@ -70,4 +87,17 @@ class SlipPrinterController extends BaseApiController
|
||||
'Content-Disposition' => 'inline; filename="' . $result['filename'] . '"',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Reports;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Reports\Stickers\StickerFormDataRequest;
|
||||
use App\Http\Requests\Reports\Stickers\StickerPrintRequest;
|
||||
use App\Http\Requests\Reports\Stickers\StickerStudentsByClassRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreUpdateRequest;
|
||||
use App\Http\Resources\Scores\ScoreStudentResource;
|
||||
use App\Models\Student;
|
||||
@@ -52,6 +52,11 @@ class FinalController extends BaseApiController
|
||||
|
||||
public function update(ScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->service->update(
|
||||
'final_exam',
|
||||
@@ -60,10 +65,10 @@ class FinalController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['scores'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year']);
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year'], $userId);
|
||||
|
||||
return response()->json(['ok' => true, 'updated' => $count]);
|
||||
}
|
||||
@@ -93,9 +98,9 @@ class FinalController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear, int $actorUserId): void
|
||||
{
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $actorUserId);
|
||||
if (empty($studentInfo)) {
|
||||
return;
|
||||
}
|
||||
@@ -104,4 +109,17 @@ class FinalController extends BaseApiController
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreAddColumnRequest;
|
||||
use App\Http\Requests\Scores\ScoreUpdateRequest;
|
||||
use App\Http\Resources\Scores\ScoreStudentResource;
|
||||
@@ -58,6 +58,11 @@ class HomeworkController extends BaseApiController
|
||||
|
||||
public function update(ScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->service->update(
|
||||
(int) $payload['class_section_id'],
|
||||
@@ -65,22 +70,27 @@ class HomeworkController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['scores'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year']);
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year'], $userId);
|
||||
|
||||
return response()->json(['ok' => true, 'updated' => $count]);
|
||||
}
|
||||
|
||||
public function addColumn(ScoreAddColumnRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$nextIndex = $this->service->addColumn(
|
||||
(int) $payload['class_section_id'],
|
||||
(string) $payload['semester'],
|
||||
(string) $payload['school_year'],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'homework_index' => $nextIndex]);
|
||||
@@ -111,9 +121,9 @@ class HomeworkController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear, int $actorUserId): void
|
||||
{
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $actorUserId);
|
||||
if (empty($studentInfo)) {
|
||||
return;
|
||||
}
|
||||
@@ -122,4 +132,17 @@ class HomeworkController extends BaseApiController
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreUpdateRequest;
|
||||
use App\Http\Resources\Scores\ScoreStudentResource;
|
||||
use App\Models\Student;
|
||||
@@ -52,6 +52,11 @@ class MidtermController extends BaseApiController
|
||||
|
||||
public function update(ScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->service->update(
|
||||
'midterm_exam',
|
||||
@@ -60,10 +65,10 @@ class MidtermController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['scores'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year']);
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year'], $userId);
|
||||
|
||||
return response()->json(['ok' => true, 'updated' => $count]);
|
||||
}
|
||||
@@ -93,9 +98,9 @@ class MidtermController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear, int $actorUserId): void
|
||||
{
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $actorUserId);
|
||||
if (empty($studentInfo)) {
|
||||
return;
|
||||
}
|
||||
@@ -104,4 +109,17 @@ class MidtermController extends BaseApiController
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreUpdateRequest;
|
||||
use App\Http\Resources\Scores\ScoreStudentResource;
|
||||
use App\Models\Student;
|
||||
@@ -56,6 +56,11 @@ class ParticipationController extends BaseApiController
|
||||
|
||||
public function update(ScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->service->update(
|
||||
(int) $payload['class_section_id'],
|
||||
@@ -63,10 +68,10 @@ class ParticipationController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['scores'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year']);
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year'], $userId);
|
||||
|
||||
return response()->json(['ok' => true, 'updated' => $count]);
|
||||
}
|
||||
@@ -96,9 +101,9 @@ class ParticipationController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear, int $actorUserId): void
|
||||
{
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $actorUserId);
|
||||
if (empty($studentInfo)) {
|
||||
return;
|
||||
}
|
||||
@@ -107,4 +112,17 @@ class ParticipationController extends BaseApiController
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreAddColumnRequest;
|
||||
use App\Http\Requests\Scores\ScoreUpdateRequest;
|
||||
use App\Http\Resources\Scores\ScoreStudentResource;
|
||||
@@ -58,6 +58,11 @@ class ProjectController extends BaseApiController
|
||||
|
||||
public function update(ScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->service->update(
|
||||
(int) $payload['class_section_id'],
|
||||
@@ -65,22 +70,27 @@ class ProjectController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['scores'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year']);
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year'], $userId);
|
||||
|
||||
return response()->json(['ok' => true, 'updated' => $count]);
|
||||
}
|
||||
|
||||
public function addColumn(ScoreAddColumnRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$nextIndex = $this->service->addColumn(
|
||||
(int) $payload['class_section_id'],
|
||||
(string) $payload['semester'],
|
||||
(string) $payload['school_year'],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'project_index' => $nextIndex]);
|
||||
@@ -111,9 +121,9 @@ class ProjectController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear, int $actorUserId): void
|
||||
{
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $actorUserId);
|
||||
if (empty($studentInfo)) {
|
||||
return;
|
||||
}
|
||||
@@ -123,4 +133,17 @@ class ProjectController extends BaseApiController
|
||||
// swallow errors to keep API response stable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreAddColumnRequest;
|
||||
use App\Http\Requests\Scores\ScoreUpdateRequest;
|
||||
use App\Http\Resources\Scores\ScoreStudentResource;
|
||||
@@ -58,6 +58,11 @@ class QuizController extends BaseApiController
|
||||
|
||||
public function update(ScoreUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$count = $this->service->update(
|
||||
(int) $payload['class_section_id'],
|
||||
@@ -65,22 +70,27 @@ class QuizController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['scores'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year']);
|
||||
$this->refreshSemesterScores((int) $payload['class_section_id'], (string) $payload['semester'], (string) $payload['school_year'], $userId);
|
||||
|
||||
return response()->json(['ok' => true, 'updated' => $count]);
|
||||
}
|
||||
|
||||
public function addColumn(ScoreAddColumnRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$nextIndex = $this->service->addColumn(
|
||||
(int) $payload['class_section_id'],
|
||||
(string) $payload['semester'],
|
||||
(string) $payload['school_year'],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'quiz_index' => $nextIndex]);
|
||||
@@ -111,9 +121,9 @@ class QuizController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
|
||||
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear, int $actorUserId): void
|
||||
{
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
|
||||
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $actorUserId);
|
||||
if (empty($studentInfo)) {
|
||||
return;
|
||||
}
|
||||
@@ -122,4 +132,17 @@ class QuizController extends BaseApiController
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreCommentListRequest;
|
||||
use App\Http\Requests\Scores\ScoreCommentSaveRequest;
|
||||
use App\Http\Requests\Scores\ScoreCommentUpdateRequest;
|
||||
@@ -72,6 +72,11 @@ class ScoreCommentController extends BaseApiController
|
||||
|
||||
public function store(ScoreCommentSaveRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->service->save(
|
||||
(int) $payload['class_section_id'],
|
||||
@@ -79,7 +84,7 @@ class ScoreCommentController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['comments'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
if (!empty($result['errors'])) {
|
||||
@@ -91,6 +96,11 @@ class ScoreCommentController extends BaseApiController
|
||||
|
||||
public function update(ScoreCommentUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$result = $this->service->update(
|
||||
(int) $payload['class_section_id'],
|
||||
@@ -98,7 +108,7 @@ class ScoreCommentController extends BaseApiController
|
||||
(string) $payload['school_year'],
|
||||
$payload['comments'] ?? [],
|
||||
$payload['reviews'] ?? [],
|
||||
(int) (auth()->id() ?? 0)
|
||||
$userId
|
||||
);
|
||||
|
||||
if (!empty($result['errors'])) {
|
||||
@@ -107,4 +117,17 @@ class ScoreCommentController extends BaseApiController
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScoreLockRequest;
|
||||
use App\Http\Requests\Scores\ScoreOverviewRequest;
|
||||
use App\Http\Requests\Scores\ScoreStudentRequest;
|
||||
@@ -19,8 +19,12 @@ class ScoreController extends BaseApiController
|
||||
|
||||
public function overview(ScoreOverviewRequest $request): JsonResponse
|
||||
{
|
||||
$teacherId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($teacherId instanceof JsonResponse) {
|
||||
return $teacherId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$teacherId = (int) ($request->user()?->id ?? (auth()->id() ?? 0));
|
||||
$classSectionId = $payload['class_section_id'] ?? $request->input('class_section_id');
|
||||
$semester = $payload['semester'] ?? $request->input('semester');
|
||||
$schoolYear = $payload['school_year'] ?? $request->input('school_year');
|
||||
@@ -45,13 +49,18 @@ class ScoreController extends BaseApiController
|
||||
|
||||
public function lock(ScoreLockRequest $request): JsonResponse
|
||||
{
|
||||
$userId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($userId instanceof JsonResponse) {
|
||||
return $userId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->service->submitScoresLock(
|
||||
(int) $payload['class_section_id'],
|
||||
(string) $payload['semester'],
|
||||
(string) $payload['school_year'],
|
||||
$payload['missing_ok'] ?? [],
|
||||
(int) ($request->user()?->id ?? (auth()->id() ?? 0))
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
@@ -59,11 +68,28 @@ class ScoreController extends BaseApiController
|
||||
|
||||
public function studentScores(ScoreStudentRequest $request): JsonResponse
|
||||
{
|
||||
$parentId = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($parentId instanceof JsonResponse) {
|
||||
return $parentId;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$parentId = (int) ($request->user()?->id ?? (auth()->id() ?? 0));
|
||||
|
||||
$data = $this->service->viewStudentScores($parentId, (string) $payload['school_year']);
|
||||
|
||||
return response()->json(['ok' => true] + $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (request()->user()?->id ?? auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Scores;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Scores\ScorePredictorRequest;
|
||||
use App\Http\Resources\Scores\ScorePredictorStudentResource;
|
||||
use App\Services\Scores\ScorePredictorService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Settings\ConfigurationStoreRequest;
|
||||
use App\Http\Requests\Settings\ConfigurationUpdateRequest;
|
||||
use App\Http\Resources\Settings\ConfigurationResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Events\EventChargeIndexRequest;
|
||||
use App\Http\Requests\Events\EventChargeUpdateRequest;
|
||||
use App\Http\Requests\Events\EventIndexRequest;
|
||||
@@ -62,11 +62,15 @@ class EventController extends BaseApiController
|
||||
|
||||
public function store(EventStoreRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
|
||||
try {
|
||||
$result = $this->managementService->create($payload, $request->file('flyer'), $actorId);
|
||||
$result = $this->managementService->create($payload, $request->file('flyer'), $guard);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Event creation failed.', ['error' => $e->getMessage()]);
|
||||
return response()->json(['ok' => false, 'message' => 'Failed to create event.'], 500);
|
||||
@@ -100,8 +104,12 @@ class EventController extends BaseApiController
|
||||
|
||||
public function destroy(int $eventId): JsonResponse
|
||||
{
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
$result = $this->managementService->delete($eventId, $actorId);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->managementService->delete($eventId, $guard);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to delete event.'], 404);
|
||||
@@ -124,8 +132,12 @@ class EventController extends BaseApiController
|
||||
|
||||
public function updateCharges(EventChargeUpdateRequest $request, int $eventId): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$actorId = (int) (auth()->id() ?? 0);
|
||||
|
||||
$result = $this->chargeService->updateParticipation(
|
||||
(int) $payload['parent_id'],
|
||||
@@ -133,7 +145,7 @@ class EventController extends BaseApiController
|
||||
$payload['participation'],
|
||||
(string) $payload['school_year'],
|
||||
(string) $payload['semester'],
|
||||
$actorId
|
||||
$guard
|
||||
);
|
||||
|
||||
if (empty($result['ok'])) {
|
||||
@@ -163,4 +175,17 @@ class EventController extends BaseApiController
|
||||
'students' => EventStudentChargeResource::collection($students),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Settings\PolicyShowRequest;
|
||||
use App\Http\Resources\Settings\PolicyResource;
|
||||
use App\Services\Policy\PolicyContentService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Preferences\PreferencesIndexRequest;
|
||||
use App\Http\Requests\Preferences\PreferencesUpsertRequest;
|
||||
use App\Http\Resources\Preferences\PreferencesCollection;
|
||||
@@ -42,12 +42,12 @@ class PreferencesController extends BaseApiController
|
||||
|
||||
public function show(): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$payload = $this->queryService->getForUser($userId);
|
||||
$payload = $this->queryService->getForUser($guard);
|
||||
|
||||
return $this->success([
|
||||
'preferences' => new PreferencesResource($payload['preferences']),
|
||||
@@ -74,19 +74,19 @@ class PreferencesController extends BaseApiController
|
||||
|
||||
public function store(PreferencesUpsertRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$saved = $this->commandService->upsert($userId, $request->validated());
|
||||
$saved = $this->commandService->upsert($guard, $request->validated());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Preferences save failed: ' . $e->getMessage());
|
||||
return $this->error('Unable to save preferences.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$payload = $this->queryService->getForUser($userId);
|
||||
$payload = $this->queryService->getForUser($guard);
|
||||
|
||||
return $this->success([
|
||||
'preferences' => new PreferencesResource($payload['preferences']),
|
||||
@@ -136,4 +136,17 @@ class PreferencesController extends BaseApiController
|
||||
|
||||
return $this->success(null, 'Preferences deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Settings\SchoolCalendarIndexRequest;
|
||||
use App\Http\Requests\Settings\SchoolCalendarOptionsRequest;
|
||||
use App\Http\Requests\Settings\SchoolCalendarStoreRequest;
|
||||
@@ -61,7 +61,14 @@ class SchoolCalendarController extends BaseApiController
|
||||
})->all();
|
||||
|
||||
if ($includeMeetings) {
|
||||
$parentUserId = $audience === 'parent' ? (int) (auth()->id() ?? 0) : null;
|
||||
$parentUserId = null;
|
||||
if ($audience === 'parent') {
|
||||
$actor = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($actor instanceof JsonResponse) {
|
||||
return $actor;
|
||||
}
|
||||
$parentUserId = $actor;
|
||||
}
|
||||
$meetingRows = $this->meetingService->listMeetings($filters['school_year'] ?? '', $audience, $parentUserId);
|
||||
foreach ($meetingRows as $row) {
|
||||
$formatted[] = $this->formatterService->formatMeetingEvent($row, $audience);
|
||||
@@ -151,4 +158,17 @@ class SchoolCalendarController extends BaseApiController
|
||||
'admins' => !empty($payload['send_email_admin']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Settings\SettingsUpdateRequest;
|
||||
use App\Http\Resources\Settings\SettingsResource;
|
||||
use App\Models\Setting;
|
||||
@@ -32,13 +32,13 @@ class SettingsController extends BaseApiController
|
||||
$settings = Setting::singleton();
|
||||
$this->authorize('update', $settings);
|
||||
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$updated = $this->settingsService->update($request->validated(), $userId);
|
||||
$updated = $this->settingsService->update($request->validated(), $guard);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Settings update failed: ' . $e->getMessage());
|
||||
return $this->error('Unable to update settings.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
@@ -48,4 +48,17 @@ class SettingsController extends BaseApiController
|
||||
'settings' => new SettingsResource($updated),
|
||||
], 'Settings updated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Staff;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Staff\StaffIndexRequest;
|
||||
use App\Http\Requests\Staff\StaffStoreRequest;
|
||||
use App\Http\Requests\Staff\StaffUpdateRequest;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Staff;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Teachers\TeacherAbsenceSubmitRequest;
|
||||
use App\Http\Requests\Teachers\TeacherClassViewRequest;
|
||||
use App\Http\Requests\Teachers\TeacherSwitchClassRequest;
|
||||
@@ -25,21 +25,21 @@ class TeacherController extends BaseApiController
|
||||
|
||||
public function classes(TeacherClassViewRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = $this->dashboardService->classView(
|
||||
$userId,
|
||||
$guard,
|
||||
$request->validated()['class_section_id'] ?? null
|
||||
);
|
||||
} catch (\RuntimeException $e) {
|
||||
return response()->json(['ok' => false, 'message' => $e->getMessage()], 403);
|
||||
}
|
||||
|
||||
$teacher = $this->teacherPayload($data['teacher'] ?? null, $userId);
|
||||
$teacher = $this->teacherPayload($data['teacher'] ?? null, $guard);
|
||||
$studentsBySection = [];
|
||||
|
||||
foreach (($data['studentsBySection'] ?? []) as $sectionId => $students) {
|
||||
@@ -59,15 +59,15 @@ class TeacherController extends BaseApiController
|
||||
|
||||
public function switchClass(TeacherSwitchClassRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$requested = (int) $request->validated()['class_section_id'];
|
||||
|
||||
try {
|
||||
$data = $this->dashboardService->classView($userId, $requested);
|
||||
$data = $this->dashboardService->classView($guard, $requested);
|
||||
} catch (\RuntimeException $e) {
|
||||
return response()->json(['ok' => false, 'message' => $e->getMessage()], 403);
|
||||
}
|
||||
@@ -87,12 +87,12 @@ class TeacherController extends BaseApiController
|
||||
|
||||
public function absenceForm(): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$data = $this->absenceService->formData($userId);
|
||||
$data = $this->absenceService->formData($guard);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
@@ -106,12 +106,12 @@ class TeacherController extends BaseApiController
|
||||
|
||||
public function submitAbsence(TeacherAbsenceSubmitRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$result = $this->absenceService->submit($userId, $request->validated());
|
||||
$result = $this->absenceService->submit($guard, $request->validated());
|
||||
|
||||
return response()->json([
|
||||
'ok' => (bool) ($result['ok'] ?? false),
|
||||
@@ -140,4 +140,17 @@ class TeacherController extends BaseApiController
|
||||
'role' => User::getUserRoleName($userId),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Staff;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Email\EmailDispatchService;
|
||||
use App\Services\Staff\StaffTimeOffLinkService;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
/**
|
||||
* Public principal acknowledgment link — sends courtesy confirmation to the requester.
|
||||
*/
|
||||
class TimeOffNotificationController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private StaffTimeOffLinkService $tokens,
|
||||
private EmailDispatchService $mail,
|
||||
) {}
|
||||
|
||||
public function notify(string $token): Response
|
||||
{
|
||||
$payload = $this->tokens->parseToken($token);
|
||||
|
||||
if (! $payload) {
|
||||
return $this->respondHtml('Sorry, this link is invalid or has expired.', 400);
|
||||
}
|
||||
|
||||
$email = trim((string) ($payload['email'] ?? ''));
|
||||
$fullName = trim((string) ($payload['name'] ?? ''));
|
||||
|
||||
if ($email === '') {
|
||||
return $this->respondHtml('Unable to notify the requester because their email was not included.', 400);
|
||||
}
|
||||
|
||||
$dates = (string) ($payload['dates'] ?? '-');
|
||||
$role = (string) ($payload['role'] ?? 'staff');
|
||||
$reason = (string) ($payload['reason'] ?? '');
|
||||
$reasonType = (string) ($payload['reason_type'] ?? '');
|
||||
$submittedAt = (string) ($payload['submitted_at'] ?? '');
|
||||
$origin = (string) ($payload['origin'] ?? 'staff portal');
|
||||
|
||||
try {
|
||||
$subject = 'TimeOff Request - Principal Acknowledgment';
|
||||
$body = '<div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:1.5;">'
|
||||
.'<p>Dear '.e($fullName !== '' ? $fullName : 'Staff Member').',</p>'
|
||||
.'<p>This is a courtesy confirmation that your time-off request submitted via the '
|
||||
.e($origin).' has been reviewed by the principal.</p>'
|
||||
.'<table cellpadding="6" cellspacing="0" style="border-collapse:collapse;">'
|
||||
.'<tr><td><strong>Role</strong></td><td>'.e($role).'</td></tr>'
|
||||
.'<tr><td><strong>Dates</strong></td><td>'.e($dates !== '' ? $dates : '-').'</td></tr>'
|
||||
.'<tr><td><strong>Reason Type</strong></td><td>'.e($reasonType !== '' ? $reasonType : '-').'</td></tr>'
|
||||
.'<tr><td><strong>Reason</strong></td><td>'.e($reason !== '' ? $reason : '-').'</td></tr>'
|
||||
.($submittedAt !== '' ? '<tr><td><strong>Submitted At</strong></td><td>'.e($submittedAt).'</td></tr>' : '')
|
||||
.'</table>'
|
||||
.'<p>If you have any follow-up questions, please contact the principal\'s office directly.</p>'
|
||||
.'<p style="margin-top:16px;">Thank you,<br>Al Rahma School Administration</p>'
|
||||
.'</div>';
|
||||
|
||||
$this->mail->send($email, $subject, $body, 'notifications');
|
||||
} catch (\Throwable $e) {
|
||||
logger()->error('Failed to send TimeOff confirmation to requester: '.$e->getMessage());
|
||||
|
||||
return $this->respondHtml(
|
||||
'Something went wrong while sending the confirmation email. Please contact IT for help.',
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
return $this->respondHtml('Confirmation email sent to the requester. You may close this window.');
|
||||
}
|
||||
|
||||
private function respondHtml(string $message, int $statusCode = 200): Response
|
||||
{
|
||||
$html = '<!DOCTYPE html><html><head><meta charset="utf-8"><title>TimeOff</title></head>'
|
||||
.'<body style="font-family:Arial,Helvetica,sans-serif;padding:24px;">'
|
||||
.'<p>'.e($message).'</p>'
|
||||
.'</body></html>';
|
||||
|
||||
return response($html, $statusCode, [
|
||||
'Content-Type' => 'text/html; charset=UTF-8',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Students;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Students\StudentAssignClassRequest;
|
||||
use App\Http\Requests\Students\StudentAssignmentListRequest;
|
||||
use App\Http\Requests\Students\StudentAutoDistributeRequest;
|
||||
@@ -676,10 +676,10 @@ class StudentController extends BaseApiController
|
||||
return response()->json(['ok' => true, 'row' => $contact]);
|
||||
}
|
||||
|
||||
public function updateRfid(Request $request, int $studentId): JsonResponse
|
||||
public function updateBadgeScan(Request $request, int $studentId): JsonResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'rfid_tag' => ['required', 'string', 'max:100'],
|
||||
'badge_scan' => ['required', 'string', 'max:100'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
@@ -694,7 +694,7 @@ class StudentController extends BaseApiController
|
||||
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
|
||||
}
|
||||
|
||||
$student->update(['rfid_tag' => $validator->validated()['rfid_tag']]);
|
||||
$student->update(['rfid_tag' => $validator->validated()['badge_scan']]);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Subjects;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Subjects\SubjectCurriculumStoreRequest;
|
||||
use App\Http\Requests\Subjects\SubjectCurriculumUpdateRequest;
|
||||
use App\Http\Resources\Subjects\SubjectClassResource;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Support;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Support\ContactSendRequest;
|
||||
use App\Http\Resources\Support\ContactMessageResource;
|
||||
use App\Services\Support\ContactMessageService;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\Support;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Requests\Support\SupportRequestIndexRequest;
|
||||
use App\Http\Requests\Support\SupportRequestStoreRequest;
|
||||
use App\Http\Resources\Support\SupportRequestCollection;
|
||||
@@ -22,9 +22,9 @@ class SupportController extends BaseApiController
|
||||
|
||||
public function index(SupportRequestIndexRequest $request): JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$this->authorize('viewAny', SupportRequest::class);
|
||||
@@ -39,7 +39,7 @@ class SupportController extends BaseApiController
|
||||
->intersect(['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'])
|
||||
->isNotEmpty();
|
||||
|
||||
$paginator = $this->supportService->list($userId, $filters, $page, $perPage, $isAdmin);
|
||||
$paginator = $this->supportService->list($guard, $filters, $page, $perPage, $isAdmin);
|
||||
$collection = new SupportRequestCollection($paginator);
|
||||
|
||||
return $this->success([
|
||||
@@ -50,8 +50,13 @@ class SupportController extends BaseApiController
|
||||
|
||||
public function store(SupportRequestStoreRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
if ($guard instanceof JsonResponse) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
if (!$user) {
|
||||
if (! $user) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -62,7 +67,7 @@ class SupportController extends BaseApiController
|
||||
$payload['user_name'] = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? ''));
|
||||
|
||||
try {
|
||||
$result = $this->supportService->create($user->id, $payload);
|
||||
$result = $this->supportService->create((int) $user->id, $payload);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Support request failed: ' . $e->getMessage());
|
||||
return $this->error('Unable to submit support request.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
@@ -80,4 +85,17 @@ class SupportController extends BaseApiController
|
||||
'page' => 'teacher_support',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|JsonResponse
|
||||
*/
|
||||
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
||||
{
|
||||
$userId = (int) (auth()->id() ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\System;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class AccessDeniedController extends Controller
|
||||
{
|
||||
/** CI route: GET /access_denied */
|
||||
public function accessDenied(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'error' => 'forbidden',
|
||||
'message' => 'Access denied.',
|
||||
], 403);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\System;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Http\Resources\System\DashboardRouteResource;
|
||||
use App\Services\Dashboard\DashboardRouteService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user