From 863e330dd84baac6e2edf3e104827ea40cb30eb1 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Mar 2026 18:44:16 -0400 Subject: [PATCH] fix some responses --- app/Models/User.php | 13 +- app/Services/Scores/HomeworkScoreService.php | 35 ++- app/Services/Scores/ScoreTermService.php | 18 ++ config/auth.php | 4 + resources/docs/openapi.json | 47 +++ response_1773266134478.json | 293 +++++++++++++++++++ routes/api.php | 22 +- 7 files changed, 415 insertions(+), 17 deletions(-) create mode 100644 response_1773266134478.json diff --git a/app/Models/User.php b/app/Models/User.php index ff93aeab..3c4a3858 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -11,8 +11,9 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Schema; use Laravel\Sanctum\HasApiTokens; +use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; -class User extends Authenticatable +class User extends Authenticatable implements JWTSubject { use HasApiTokens; use HasFactory; @@ -65,6 +66,16 @@ class User extends Authenticatable 'updated_at' => 'datetime', ]; + public function getJWTIdentifier() + { + return $this->getKey(); + } + + public function getJWTCustomClaims() + { + return []; + } + /* ============================================================ * Relationships * ============================================================ diff --git a/app/Services/Scores/HomeworkScoreService.php b/app/Services/Scores/HomeworkScoreService.php index d0a6b5e7..827f24b8 100644 --- a/app/Services/Scores/HomeworkScoreService.php +++ b/app/Services/Scores/HomeworkScoreService.php @@ -19,12 +19,16 @@ class HomeworkScoreService $semester = $this->term->semesterLabel($semester); $schoolYear = $this->term->schoolYear($schoolYear); $semVariants = $this->term->semesterVariants($semester); + $schoolYearVariants = $this->term->schoolYearVariants($schoolYear); + if (empty($schoolYearVariants)) { + $schoolYearVariants = [$schoolYear]; + } $headerRows = Homework::query() ->select('homework_index') ->where('class_section_id', $classSectionId) ->whereIn('semester', $semVariants) - ->where('school_year', $schoolYear) + ->whereIn('school_year', $schoolYearVariants) ->orderBy('homework_index') ->get(); @@ -32,7 +36,7 @@ class HomeworkScoreService $studentIds = StudentClass::query() ->where('class_section_id', $classSectionId) - ->where('school_year', $schoolYear) + ->whereIn('school_year', $schoolYearVariants) ->pluck('student_id') ->map(fn ($v) => (int) $v) ->all(); @@ -55,7 +59,7 @@ class HomeworkScoreService ->select('student_id', 'homework_index', 'score') ->where('class_section_id', $classSectionId) ->whereIn('semester', $semVariants) - ->where('school_year', $schoolYear) + ->whereIn('school_year', $schoolYearVariants) ->get() ->map(fn ($row) => $row->toArray()) ->all(); @@ -78,11 +82,32 @@ class HomeworkScoreService 'headers' => $headers, 'semester' => $semester, 'schoolYear' => $schoolYear, - 'scoresLocked' => GradingLock::isLocked($classSectionId, $semester, $schoolYear), - 'missingOkMap' => MissingScoreOverride::getOverridesMap($classSectionId, $semester, $schoolYear, 'homework'), + 'scoresLocked' => $this->isLockedForAnySchoolYear($classSectionId, $semester, $schoolYearVariants), + 'missingOkMap' => $this->getMissingOverridesForAnySchoolYear($classSectionId, $semester, $schoolYearVariants), ]; } + private function isLockedForAnySchoolYear(int $classSectionId, string $semester, array $schoolYearVariants): bool + { + foreach ($schoolYearVariants as $year) { + if (GradingLock::isLocked($classSectionId, $semester, $year)) { + return true; + } + } + return false; + } + + private function getMissingOverridesForAnySchoolYear(int $classSectionId, string $semester, array $schoolYearVariants): array + { + foreach ($schoolYearVariants as $year) { + $map = MissingScoreOverride::getOverridesMap($classSectionId, $semester, $year, 'homework'); + if (!empty($map)) { + return $map; + } + } + return []; + } + public function update(int $classSectionId, string $semester, string $schoolYear, array $scores, array $missingOk, int $updatedBy): int { if (GradingLock::isLocked($classSectionId, $semester, $schoolYear)) { diff --git a/app/Services/Scores/ScoreTermService.php b/app/Services/Scores/ScoreTermService.php index d57d820f..1ab6eb47 100644 --- a/app/Services/Scores/ScoreTermService.php +++ b/app/Services/Scores/ScoreTermService.php @@ -44,6 +44,24 @@ class ScoreTermService return (string) (Configuration::getConfig('school_year') ?? ''); } + public function schoolYearVariants(?string $input): array + { + $value = trim((string) $input); + if ($value === '') { + return []; + } + + $variants = [ + $value, + str_replace('_', '-', $value), + str_replace('-', '_', $value), + str_replace('/', '-', $value), + str_replace('/', '_', $value), + ]; + + return array_values(array_unique(array_filter($variants, static fn ($v) => $v !== ''))); + } + public function semesterVariants(?string $semester): array { $raw = trim((string) $semester); diff --git a/config/auth.php b/config/auth.php index 52432aa2..a4b7ef7e 100755 --- a/config/auth.php +++ b/config/auth.php @@ -44,6 +44,10 @@ return [ 'driver' => 'jwt', 'provider' => 'users', ], + 'sanctum' => [ + 'driver' => 'sanctum', + 'provider' => 'users', + ], ], /* diff --git a/resources/docs/openapi.json b/resources/docs/openapi.json index 743f1dfd..eb3889fa 100755 --- a/resources/docs/openapi.json +++ b/resources/docs/openapi.json @@ -4060,6 +4060,53 @@ } } }, + "/api/v1/scores/homework": { + "get": { + "operationId": "getHomeworkScores", + "tags": ["Scores"], + "summary": "HomeworkController::index", + "security": [{"bearerAuth": []}], + "parameters": [ + { + "name": "class_section_id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "semester", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "school_year", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": {"description": "OK"}, + "401": {"$ref": "#/components/responses/UnauthorizedError"}, + "422": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, "/api/v1/time": { "get": { "operationId": "getServerTime", diff --git a/response_1773266134478.json b/response_1773266134478.json new file mode 100644 index 00000000..082416e8 --- /dev/null +++ b/response_1773266134478.json @@ -0,0 +1,293 @@ +{ + "message": "PHPOpenSourceSaver\\JWTAuth\\JWT::fromUser(): Argument #1 ($user) must be of type PHPOpenSourceSaver\\JWTAuth\\Contracts\\JWTSubject, App\\Models\\User given, called in /opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php on line 363", + "exception": "TypeError", + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/php-open-source-saver/jwt-auth/src/JWT.php", + "line": 81, + "trace": [ + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php", + "line": 363, + "function": "fromUser", + "class": "PHPOpenSourceSaver\\JWTAuth\\JWT", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/app/Http/Controllers/Api/Auth/AuthController.php", + "line": 42, + "function": "__callStatic", + "class": "Illuminate\\Support\\Facades\\Facade", + "type": "::" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Controller.php", + "line": 54, + "function": "login", + "class": "App\\Http\\Controllers\\Api\\Auth\\AuthController", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php", + "line": 43, + "function": "callAction", + "class": "Illuminate\\Routing\\Controller", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Route.php", + "line": 265, + "function": "dispatch", + "class": "Illuminate\\Routing\\ControllerDispatcher", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Route.php", + "line": 211, + "function": "runController", + "class": "Illuminate\\Routing\\Route", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Router.php", + "line": 822, + "function": "run", + "class": "Illuminate\\Routing\\Route", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 180, + "function": "Illuminate\\Routing\\{closure}", + "class": "Illuminate\\Routing\\Router", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php", + "line": 50, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Routing\\Middleware\\SubstituteBindings", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 137, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Router.php", + "line": 821, + "function": "then", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Router.php", + "line": 800, + "function": "runRouteWithinStack", + "class": "Illuminate\\Routing\\Router", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Router.php", + "line": 764, + "function": "runRoute", + "class": "Illuminate\\Routing\\Router", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Routing/Router.php", + "line": 753, + "function": "dispatchToRoute", + "class": "Illuminate\\Routing\\Router", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php", + "line": 200, + "function": "dispatch", + "class": "Illuminate\\Routing\\Router", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 180, + "function": "Illuminate\\Foundation\\Http\\{closure}", + "class": "Illuminate\\Foundation\\Http\\Kernel", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php", + "line": 21, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php", + "line": 31, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php", + "line": 21, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php", + "line": 51, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Middleware\\TrimStrings", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Http/Middleware/ValidatePostSize.php", + "line": 27, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Http\\Middleware\\ValidatePostSize", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php", + "line": 109, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php", + "line": 74, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Http\\Middleware\\HandleCors", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php", + "line": 58, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Http\\Middleware\\TrustProxies", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/InvokeDeferredCallbacks.php", + "line": 22, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Middleware\\InvokeDeferredCallbacks", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Http/Middleware/ValidatePathEncoding.php", + "line": 26, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 219, + "function": "handle", + "class": "Illuminate\\Http\\Middleware\\ValidatePathEncoding", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", + "line": 137, + "function": "Illuminate\\Pipeline\\{closure}", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php", + "line": 175, + "function": "then", + "class": "Illuminate\\Pipeline\\Pipeline", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php", + "line": 144, + "function": "sendRequestThroughRouter", + "class": "Illuminate\\Foundation\\Http\\Kernel", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/Application.php", + "line": 1220, + "function": "handle", + "class": "Illuminate\\Foundation\\Http\\Kernel", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/public/index.php", + "line": 20, + "function": "handleRequest", + "class": "Illuminate\\Foundation\\Application", + "type": "->" + }, + { + "file": "/opt/lampp/htdocs/alrahma_sunday_school_api/vendor/laravel/framework/src/Illuminate/Foundation/resources/server.php", + "line": 23, + "function": "require_once" + } + ] +} \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index d878b1bf..d1255e9d 100755 --- a/routes/api.php +++ b/routes/api.php @@ -120,8 +120,8 @@ Route::prefix('v1')->group(function () { Route::post('register', [RegisterController::class, 'store']); Route::post('login', [AuthController::class, 'login']); Route::post('refresh', [AuthController::class, 'refresh'])->middleware('jwt.auth'); - Route::post('logout', [AuthController::class, 'logout'])->middleware('auth.multi'); - Route::get('me', [AuthController::class, 'me'])->middleware('auth.multi'); + Route::post('logout', [AuthController::class, 'logout'])->middleware('auth:api'); + Route::get('me', [AuthController::class, 'me'])->middleware('auth:api'); }); Route::prefix('policies')->group(function () { @@ -145,13 +145,13 @@ Route::prefix('v1')->group(function () { Route::get('call-to-action', [FrontendController::class, 'callToAction']); Route::get('testimonial', [FrontendController::class, 'testimonial']); Route::get('not-found', [FrontendController::class, 'notFound']); - Route::get('me', [FrontendController::class, 'fetchUser'])->middleware('auth.multi'); + Route::get('me', [FrontendController::class, 'fetchUser'])->middleware('auth:api'); }); Route::get('health', [HealthController::class, 'index']); Route::get('system/db-check', [DatabaseHealthController::class, 'index']); - Route::middleware('auth.multi')->prefix('preferences')->group(function () { + Route::middleware('auth:api')->prefix('preferences')->group(function () { Route::get('/', [PreferencesController::class, 'show']); Route::post('/', [PreferencesController::class, 'store']); Route::get('list', [PreferencesController::class, 'index']); @@ -160,7 +160,7 @@ Route::prefix('v1')->group(function () { Route::delete('{userId}', [PreferencesController::class, 'destroy']); }); - Route::middleware('auth.multi')->prefix('nav-builder')->group(function () { + Route::middleware('auth:api')->prefix('nav-builder')->group(function () { Route::get('menu', [NavBuilderController::class, 'menu']); Route::get('data', [NavBuilderController::class, 'data']); Route::post('/', [NavBuilderController::class, 'store']); @@ -168,7 +168,7 @@ Route::prefix('v1')->group(function () { Route::post('reorder', [NavBuilderController::class, 'reorder']); }); - Route::middleware('auth.multi')->prefix('landing')->group(function () { + Route::middleware('auth:api')->prefix('landing')->group(function () { Route::get('/', [LandingPageController::class, 'index']); Route::get('teacher', [LandingPageController::class, 'teacher']); Route::get('parent', [LandingPageController::class, 'parent']); @@ -178,11 +178,11 @@ Route::prefix('v1')->group(function () { Route::get('guest', [LandingPageController::class, 'guest']); }); - Route::middleware('auth.multi')->prefix('info-icon')->group(function () { + Route::middleware('auth:api')->prefix('info-icon')->group(function () { Route::get('profile', [InfoIconController::class, 'profileIcon']); }); - Route::middleware('auth.multi')->prefix('administrator')->group(function () { + Route::middleware('auth:api')->prefix('administrator')->group(function () { Route::get('absence', [AdministratorAbsenceController::class, 'index']); Route::post('absence', [AdministratorAbsenceController::class, 'store']); @@ -211,7 +211,7 @@ Route::prefix('v1')->group(function () { Route::delete('emergency-contacts/{contactId}', [AdministratorEmergencyContactController::class, 'destroy']); }); - Route::middleware('auth.multi')->prefix('attendance')->group(function () { + Route::middleware('auth:api')->prefix('attendance')->group(function () { // Teacher Route::get('/teacher/grid', [TeacherAttendanceApiController::class, 'grid']); Route::get('/teacher/form', [TeacherAttendanceApiController::class, 'form']); @@ -254,7 +254,7 @@ Route::prefix('v1')->group(function () { Route::get('/class-assignment-data', [AssignmentApiController::class, 'classAssignmentData']); }); - Route::middleware('auth.multi')->group(function () { + Route::middleware('auth:api')->group(function () { Route::get('dashboard/route', [DashboardController::class, 'route']); Route::prefix('utilities/phone')->group(function () { @@ -836,7 +836,7 @@ Route::prefix('attendance-tracking')->group(function () { Route::post('save-notification-note', [AttendanceTrackingController::class, 'saveNotificationNote']); }); -Route::middleware('auth.multi')->group(function () { +Route::middleware('auth:api')->group(function () { Route::prefix('assignments')->group(function () { Route::get('/', [AssignmentApiController::class, 'index']); Route::post('/', [AssignmentApiController::class, 'store']);