diff --git a/.composer/.htaccess b/.composer/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/.composer/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/.composer/cache/.htaccess b/.composer/cache/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/.composer/cache/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/.env.azuredevops b/.env.azuredevops index c7ce47a..62163a7 100644 --- a/.env.azuredevops +++ b/.env.azuredevops @@ -31,6 +31,11 @@ COPILOT_DB_DATABASE=#{copilot.database}# # connection info for PCI Forms db connection PCIFORMS_DB_DATABASE=#{pciforms.database}# +# Azure Entra ID Credentials +AZURE_CLIENT_ID=#{azure.client.id}# +AZURE_CLIENT_SECRET=#{azure.client.secret}# +AZURE_TENANT_ID=#{azure.tenant.id}# +AZURE_REDIRECT_URI=#{azure.redirect.uri}# BROADCAST_DRIVER=#{broadcast.driver}# CACHE_DRIVER=#{cache.driver}# @@ -59,18 +64,6 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" JWT_SECRET=#{jwt.secret}# -# Config for ADLDAP authentication -ADLDAP_CONTROLLERS=#{adldap.controllers}# -ADLDAP_BASEDN=#{adldap.basedn}# -ADLDAP_PORT=#{adldap.port}# -ADLDAP_ADMIN_USERNAME="#{adldap.username}#" -ADLDAP_ADMIN_PASSWORD="#{adldap.password}#" -ADLDAP_USE_SSL=#{adldap.useSSL}# -ADLDAP_USE_TLS=#{adldap.useTLS}# - -# Complete distinguished name of group to which to limit admin dashboard access -ADMIN_GROUP="#{admin.group}#" - # Client id/key used for test cases TEST_CLIENTID= TEST_CLIENTKEY= diff --git a/.env.example b/.env.example index 7767a58..8dce4eb 100644 --- a/.env.example +++ b/.env.example @@ -64,6 +64,12 @@ COPILOT_DB_DATABASE= COPILOT_DB_USERNAME= COPILOT_DB_PASSWORD= +# Azure Entra ID Credentials +AZURE_CLIENT_ID= +AZURE_CLIENT_SECRET= +AZURE_TENANT_ID= +AZURE_REDIRECT_URI= + BROADCAST_DRIVER=log CACHE_DRIVER=file SESSION_DRIVER=file @@ -91,18 +97,6 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" JWT_SECRET= -# Config for ADLDAP authentication -ADLDAP_CONTROLLERS= -ADLDAP_BASEDN= -ADLDAP_PORT=636 -ADLDAP_ADMIN_USERNAME= -ADLDAP_ADMIN_PASSWORD= -ADLDAP_USE_SSL=true -ADLDAP_USE_TLS=false - -# Complete distinguished name of group to which to limit admin dashboard access -ADMIN_GROUP= - # Client id/key used for test cases TEST_CLIENTID= TEST_CLIENTKEY= diff --git a/.gitignore b/.gitignore index 35cfb75..3954011 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ yarn-error.log .env .DS_Store /storage/api-docs +/docker/nginx/ssl diff --git a/app/Http/.DS_Store b/app/Http/.DS_Store index 43c267d..5008ddf 100644 Binary files a/app/Http/.DS_Store and b/app/Http/.DS_Store differ diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 6458cbf..bd264fc 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -8,6 +8,8 @@ use Illuminate\Support\Facades\Hash; use App\Models\Client; + + class AdminController extends Controller { public function __construct() @@ -18,6 +20,7 @@ public function __construct() public function index() { $client_data = Client::all(); + //dd($client_data); return view('admin.index', ['data' => $client_data ]); } @@ -57,7 +60,7 @@ public function deleteClient($id){ //delete client try { Client::destroy($id); - Log::info(sprintf("Client %d deleted by %s.", $id, Auth::user()->getUserPrincipalName())); + Log::info(sprintf("Client %d deleted", $id)); } catch ( \Exception $e ) { Log::error($e->getMessage()); return redirect()->back()->withError("There was an error while deleting the client."); @@ -67,7 +70,9 @@ public function deleteClient($id){ } public function addClientShow() { - return view('admin.addclient'); + // Get available permissions + $permissions = config('permissions'); + return view('admin.addclient', compact('permissions')); } public function addClientPost(Request $request) { @@ -77,7 +82,7 @@ public function addClientPost(Request $request) { 'clienturl' => 'required' ]); - $form_input = $request->only('clientname', 'clienturl'); + $form_input = $request->only('clientname', 'clienturl', 'permissions'); $new_clientkey = Client::generateClientKey(); @@ -86,9 +91,17 @@ public function addClientPost(Request $request) { $newclient->clienturl = $form_input['clienturl']; $newclient->clientid = Client::generateClientID(); $newclient->password = Hash::make($new_clientkey); + $newclient->created_by = Auth::id(); try { $newclient->save(); + + // Sync permissions after the client is saved + if (isset($form_input['permissions'])) { + $newclient->syncPermissionsByName($form_input['permissions']); + } else { + $newclient->syncPermissionsByName([]); + } } catch ( \Exception $e ) { return redirect()->back()->withError("There was an error while adding the client."); @@ -97,6 +110,63 @@ public function addClientPost(Request $request) { return view('admin.addclient')->with('success', true) ->with('clientname', $newclient->clientname) ->with('clientid', $newclient->clientid) - ->with('clientkey', $new_clientkey); + ->with('clientkey', $new_clientkey) + ->with('set_permissions', $form_input['permissions'] ?? []); + } + + /** + * Edit an existing client + * + * @param Request $request + * @param int $id + * @return \Illuminate\View\View + */ + public function updateClient(Request $request, $id) + { + // Get available permissions + $permissions = config('permissions'); + + // Get the client to edit + $client = Client::findOrFail($id); + + return view('admin.updateclient', compact('client', 'permissions')); + } + + public function updateClientPut(Request $request, $id) + { + $this->validate($request, [ + 'clientname' => 'required', + 'clienturl' => 'required|url' + ]); + + $form_input = $request->only('clientname', 'clienturl', 'permissions'); + + try { + // Find the existing client + $client = Client::findOrFail($id); + + // Update client details + $client->clientname = $form_input['clientname']; + $client->clienturl = $form_input['clienturl']; + $client->save(); + + // Sync permissions + if (isset($form_input['permissions'])) { + $client->syncPermissionsByName($form_input['permissions']); + } else { + $client->syncPermissionsByName([]); + } + + return redirect() + ->route('admin.client.update', ['id' => $id]) + ->with('success', 'Client updated successfully.'); + + } catch (\Exception $e) { + Log::error('Error updating client: ' . $e->getMessage()); + return redirect() + ->back() + ->withInput() + ->withError('There was an error while updating the client.'); + } } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index a07c962..708a0e8 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -10,21 +10,10 @@ use Tymon\JWTAuth\Exceptions\TokenInvalidException; use Tymon\JWTAuth\JWTAuth; use Illuminate\Support\Facades\Hash; +use App\Http\Resources\AuthTokenResource; /** - * @OA\SecurityScheme( - * type="http", - * securityScheme="jwtAuth", - * scheme="bearer", - * bearerFormat="JWT", - * in="header", - * ) - * @OA\SecurityScheme( - * type="http", - * securityScheme="basicAuth", - * scheme="basic", - * in="header", - * ) + * Authentication Controller */ class AuthController extends Controller { @@ -35,69 +24,64 @@ class AuthController extends Controller */ public function __construct() { - $this->middleware('auth:api', ['except' => ['login']]); + $this->middleware('auth:api', ['except' => ['internalLogin', 'publicLogin']]); } /** - * Get a JWT via given credentials. - * - * @return \Illuminate\Http\JsonResponse - * - * @OA\Post( - * path="/api/v1/auth/login", - * operationId="login", - * summary="Get JWT auth token", - * description="Get JSON Web Token for Authentication", - * @OA\RequestBody( - * @OA\MediaType( - * mediaType="application/x-www-form-urlencoded", - * @OA\Schema( - * type="object", - * @OA\Property( - * property="clientid", - * type="string", - * ), - * @OA\Property( - * property="clientkey", - * type="string", - * ) - * ) - * ) - * ), - * @OA\Response( - * response=200, - * description="Successful Operation", - * @OA\JsonContent( - * @OA\Property( - * property="access_token", - * description="JWT Access Token", - * type="string", - * ), - * @OA\Property( - * property="token_type", - * description="Token Type- always 'bearer'", - * type="string", - * ), - * @OA\Property( - * property="expires_in", - * description="Token expiration time in seconds", - * type="integer", - * ), - * ), - * ) - * ) + * Login on Internal API Server + * + * Pass in the clientid and clientkey as parameters, and a token will be returned. + * + * **Note**: This endpoint is only available on the internal API server. + * + * @param \Illuminate\Http\Request $request + * + * @return AuthTokenResource */ - public function login() + public function internalLogin(Request $request) { - /*$credentials = request(['clientid', 'clientkey']); + $validated = $request->validate([ + /** @query */ + 'clientid' => ['required', 'string'], + /** @query */ + 'clientkey' => ['required', 'string'], + ]); + return $this->performLogin($request); + } - if (! $token = auth()->attempt($credentials)) { - return response()->json(['error' => 'Unauthorized'], 401); - }*/ + /** + * Login on Public API Server + * + * Pass in the clientid and clientkey as parameters, and a token will be returned. + * + * **Note**: This endpoint is only available on the public API server. + * + * @param \Illuminate\Http\Request $request + * + * @return AuthTokenResource + */ + public function publicLogin(Request $request) + { + $validated = $request->validate([ + /** @query */ + 'clientid' => ['required', 'string'], + /** @query */ + 'clientkey' => ['required', 'string'], + ]); + return $this->performLogin($request); + } + /** + * Shared Login Method + * + * @param \Illuminate\Http\Request $request + * + * @return AuthTokenResource + */ + public function performLogin(Request $request) + { try { - //Config::set('auth.providers.users.model', \App\Models\Client::class); - $req_creds = request()->only('clientid', 'clientkey'); + $req_creds = $request->only('clientid', 'clientkey'); $creds = [ 'clientid' => $req_creds['clientid'], 'password' => $req_creds['clientkey'] ]; if (! $token = auth()->guard('api')->attempt($creds)) { @@ -151,50 +135,13 @@ public function refresh() * * @param string $token * - * @return \Illuminate\Http\JsonResponse + * @return AuthTokenResource */ protected function respondWithToken($token) { - return response()->json([ + return new AuthTokenResource([ 'access_token' => $token, - 'token_type' => 'bearer', 'expires_in' => auth()->factory()->getTTL() * 60 ]); } } - /** - * @var \Tymon\JWTAuth\JWTAuth - */ - /* - protected $auth; - - public function __construct(JWTAuth $auth) - { - $this->auth = $auth; - } - - public function loginPost(Request $request) - { - $this->validate($request, [ - 'clientid' => 'required', - 'clientkey' => 'required', - ]); - - try { - $req_creds = $request->only('clientid', 'clientkey'); - $creds = [ 'clientid' => $req_creds['clientid'], 'password' => $req_creds['clientkey'] ]; - - if (! $token = $this->auth->attempt($creds)) { - return response()->json(['user_not_found'], 404); - } - } catch (TokenExpiredException $e) { - return response()->json(['token_expired'], $e->getStatusCode()); - } catch (TokenInvalidException $e) { - return response()->json(['token_invalid'], $e->getStatusCode()); - } catch (JWTException $e) { - return response()->json(['token_absent' => $e->getMessage()], $e->getStatusCode()); - } - - return response()->json(compact('token')); - } -}*/ diff --git a/app/Http/Controllers/ClassScheduleController.php b/app/Http/Controllers/ClassScheduleController.php index 51d40fc..30e488e 100644 --- a/app/Http/Controllers/ClassScheduleController.php +++ b/app/Http/Controllers/ClassScheduleController.php @@ -5,13 +5,7 @@ use App\Models\ClassSchedule; use Illuminate\Http\Request; use App\Exceptions\MissingParameterException; -use League\Fractal\Manager; -use League\Fractal\Resource\Item; -use League\Fractal\Resource\Collection; -use App\Http\Transformers\ClassScheduleTransformer; -use App\Http\Serializers\CustomDataArraySerializer; -use DB; - +use App\Http\Resources\ClassScheduleCollection; class ClassScheduleController extends ApiController{ @@ -22,17 +16,13 @@ class ClassScheduleController extends ApiController{ * Status: inactive * No route, not yet serialized **/ - public function getClassSchedules($psclassid, Request $request){ - $schedules = ClassSchedule::where('PSClassID', '=', $psclassid)->get(); - - $data = $schedules; - if ( !is_null($schedules) ) { - $collection = new Collection($schedules, new ClassScheduleTransformer, self::WRAPPER); - - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); + public function getClassSchedules($psclassid, Request $request) + { + try { + $schedules = ClassSchedule::where('PSClassID', '=', $psclassid)->get(); + return new ClassScheduleCollection($schedules); + } catch (\Exception $e) { + return response()->json(['classSchedules' => []], 404); } - return $this->respond($data); } } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index e26c68e..06fcb55 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -8,48 +8,5 @@ class Controller extends BaseController { - /** - * @OA\Info( - * version=APP_VERSION, - * title="Bellevue College Data API", - * description="The Bellevue College Data API is used to serve and collect BC data.", - * @OA\Contact( - * email="admin@admin.com" - * ), - * @OA\License( - * name="Apache 2.0", - * url="http://www.apache.org/licenses/LICENSE-2.0.html" - * ) - * ) - * - * @OA\Server( - * url=PUBLIC_URL, - * description="Primary API Server" - * ) - * @OA\Server( - * url=PRIVATE_URL, - * description="Private API Server" - * ) - * @OA\PathItem( - * path="/api/v1/internal", - * @OA\Server( - * url=PRIVATE_URL, - * description="Private API Server" - * ) - * ) - * - * @OA\Tag( - * name="Employees", - * description="API Endpoints for Employee Data" - * ) - * @OA\Tag( - * name="Directory", - * description="API Endpoints for Employee Directory Data" - * ) - * @OA\Tag( - * name="Internal", - * description="API Endpoints available on the internal domain" - * ) - */ use AuthorizesRequests, DispatchesJobs, ValidatesRequests; } diff --git a/app/Http/Controllers/CourseController.php b/app/Http/Controllers/CourseController.php index 65ab1d5..2172e31 100644 --- a/app/Http/Controllers/CourseController.php +++ b/app/Http/Controllers/CourseController.php @@ -3,24 +3,22 @@ namespace App\Http\Controllers; use App\Models\Course; +use App\Http\Resources\CourseResource; +use App\Http\Resources\CourseCollection; use Illuminate\Http\Request; use App\Exceptions\MissingParameterException; -use League\Fractal\Manager; -use League\Fractal\Resource\Item; -use League\Fractal\Resource\Collection; -use App\Http\Transformers\CourseTransformer; -use App\Http\Serializers\CustomDataArraySerializer; -use DB; class CourseController extends ApiController{ const WRAPPER = "courses"; /** - Get all courses. This should probably never be used. - Status: inactive - No active route exists. - **/ + * Get all courses. + * + * Inactive: No active route exists, should not be used + * + * @return \Illuminate\Http\JsonResponse + **/ public function index(){ $courses = Course::all(); @@ -29,118 +27,110 @@ public function index(){ } /** - Get a course based on a given CourseID. + * Get Course by CourseID + * + * Course ID is a combination of the Course Subject and Catalog Number, space separated + * + * @param string $courseid + * + * @return CourseResource | \Illuminate\Http\JsonResponse **/ - public function getCourse($courseid) + public function getCourse(string $courseid, Request $request) { - - $course = Course::where('CourseID', '=', $courseid)->active()->first(); - - $data = $course; - if ( !is_null($course) ) { - $item = new Item($course, new CourseTransformer, "course"); - - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($item)->toArray(); + try { + $course = Course::where('CourseID', '=', $courseid)->active()->firstOrFail(); + return new CourseResource($course); + } catch (\Exception $e) { + return response()->json(['courses' => []], 404); } - return $this->respond($data); } /** - Get a course based on a given subject and course number. + * Get Course by Subject and Catalog Number + * + * @param string $subject + * @param string $coursenum + * + * @return CourseResource | \Illuminate\Http\JsonResponse **/ public function getCourseBySubjectAndNumber($subject, $coursenum){ - - $course = Course::where('CourseSubject', '=', $subject) - ->where('CatalogNumber', '=', $coursenum) - ->active() - ->first(); - - $data = $course; - if ( !is_null($course) ) { - $item = new Item($course, new CourseTransformer, "course"); - - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($item)->toArray(); + try { + $course = Course::where('CourseSubject', '=', $subject) + ->where('CatalogNumber', '=', $coursenum) + ->active() + ->firstOrFail(); + return new CourseResource($course); + } catch (\Exception $e) { + return response()->json(['courses' => []], 404); } - return $this->respond($data); } - /** - Get active courses based on a given subject. + /** + * List Active Courses by Subject + * + * @param string $subject + * + * @return CourseCollection | \Illuminate\Http\JsonResponse **/ public function getCoursesBySubject($subject) { - - $courses = Course::where('CourseSubject', '=', $subject) - ->where(function ($query) { - $query->where('CourseTitle2', '<>', 'Transfer In Course') - ->where('CourseTitle', '<>', 'Transferred-In Course'); - }) - ->orderBy('CourseId', 'asc') - ->active() - ->get(); - - $data = $courses; - if ( !is_null($courses) ) { - $collection = new Collection($courses, new CourseTransformer, self::WRAPPER); - - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); + try { + $courses = Course::where('CourseSubject', '=', $subject) + ->notTransferIn() + ->active() + ->orderBy('CourseId', 'asc') + ->get(); + + return new CourseCollection($courses); + } catch (\Exception $e) { + return response()->json(['courses' => []], 404); } - return $this->respond($data); } /** - Get multiple courses based on course numbers passed via courses[] query parameter + * Get Multiple Courses by CourseID + * + * Courses are passed as an array via the courses[] query parameter + * + * @param \Illuminate\Http\Request $request + * + * @return CourseCollection | \Illuminate\Http\JsonResponse **/ - public function getMultipleCourses(Request $request){ - - $course_input = $request->input('courses'); - if ( !is_array($course_input) ) { - //be nice and don't fail non-array input for the case there's a single value - $course_input[] = $course_input; - } - //dd($course_input); - if ( !empty($course_input) && count($course_input) > 0 ) { - //valid courses parameter so get courses - - //strip whitespace so we can do db comparison - $courses_stripped = $course_input; - array_walk($courses_stripped, array($this, 'stripWhitespace')); - $placeholder = implode(', ', array_fill(0, count($courses_stripped), '?')); - - //DB::connection('ods')->enableQueryLog(); - $courses = Course::whereRaw("REPLACE(CourseID, ' ', '') IN ($placeholder)", $courses_stripped)->active()->get(); - //$queries = DB::connection('ods')->getQueryLog(); - //dd($queries); - - $data = $courses; - if ( !is_null($courses) ) { - $collection = new Collection($courses, new CourseTransformer, self::WRAPPER); - - //define serializer - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); + public function getMultipleCourses(Request $request) + { + $validated = $request->validate([ + 'courses' => 'required|array', + ]); + try { + $course_input = $request->input('courses'); + + if ( !empty($course_input) && count($course_input) > 0 ) { + //valid courses parameter so get courses + //strip whitespace so we can do db comparison + $courses_stripped = $course_input; + array_walk($courses_stripped, array($this, 'stripWhitespace')); + $placeholder = implode(', ', array_fill(0, count($courses_stripped), '?')); + + $courses = Course::whereRaw("REPLACE(CourseID, ' ', '') IN ($placeholder)", $courses_stripped)->active()->get(); + return new CourseCollection($courses); + } else { + throw new MissingParameterException("Invalid courses[] parameter provided."); } - - return $this->respond($data); - } else { - throw new MissingParameterException("Invalid courses[] parameter provided."); + } catch (\Exception $e) { + return response()->json(['courses' => []], 404); } - } /** * Function to strip whitespace via regex + * + * @param string $value + * @param string $key + * + * @return void **/ private function stripWhitespace(&$value, $key){ $value = preg_replace('/\s+/', '', $value); } -} -?> +} \ No newline at end of file diff --git a/app/Http/Controllers/CourseYearQuarterController.php b/app/Http/Controllers/CourseYearQuarterController.php index e3123ed..c49aef5 100644 --- a/app/Http/Controllers/CourseYearQuarterController.php +++ b/app/Http/Controllers/CourseYearQuarterController.php @@ -3,15 +3,11 @@ namespace App\Http\Controllers; use App\Models\CourseYearQuarter; -use App\Http\Transformers\CourseYearQuarterTransformer; +use App\Http\Resources\CourseYearQuarterResource; +use App\Http\Resources\CourseYearQuarterCollection; use App\Http\Controllers\Controller; -use App\Http\Serializers\CourseDataArraySerializer; -use App\Http\Serializers\CustomDataArraySerializer; use Illuminate\Http\Request; -use League\Fractal\Manager; -use League\Fractal\Resource\Collection; -use League\Fractal\Resource\Item; -use DB; + class CourseYearQuarterController extends ApiController { @@ -19,95 +15,56 @@ class CourseYearQuarterController extends ApiController { /** * Return a CourseYearQuarter based on a YearQuarterID, subject, and course number. + * + * @param string $yqrid YearQuarterID + * @param string $subjectid SubjectID + * @param string $coursenum CourseNumber + * @param \Illuminate\Http\Request $request + * + * @return CourseYearQuarterResource | \Illuminate\Http\JsonResponse **/ public function getCourseYearQuarter($yqrid, $subjectid, $coursenum, Request $request) { - if ($request->input('format') === 'strm'){ - //DB::connection('ods')->enableQueryLog(); - $cyq = CourseYearQuarter::where('STRM', '=', $yqrid) - ->where('Department', '=', $subjectid) - ->where('CourseNumber', '=', $coursenum) - ->first(); - //$queries = DB::connection('ods')->getQueryLog(); - //dd($queries); - //var_dump($cyq); - } else { - //DB::connection('ods')->enableQueryLog(); - $cyq = CourseYearQuarter::where('YearQuarterID', '=', $yqrid) + $validated = $request->validate([ + 'format' => 'sometimes|string|in:yrq,strm', + ]); + try { + $selector = $request->input('format') === 'strm' ? 'STRM' : 'YearQuarterID'; + $cyq = CourseYearQuarter::where($selector, '=', $yqrid) ->where('Department', '=', $subjectid) ->where('CourseNumber', '=', $coursenum) - ->first(); - //$queries = DB::connection('ods')->getQueryLog(); - //dd($queries); - //var_dump($cyq); + ->firstOrFail(); + + return new CourseYearQuarterResource($cyq); + } catch (\Exception $e) { + return response()->json(['classes' => []], 404); } - - - $data = $cyq; - - //handle gracefully if null - if ( !is_null($cyq) ) { - $item = new Item($cyq, new CourseYearQuarterTransformer, self::WRAPPER); - - //define serializer - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($item)->toArray(); - } - - return $this->respond($data); } /** * Return CourseYearQuarters based on a given YearQuarterID and subject. + * + * @param string $yqrid YearQuarterID + * @param string $subjectid SubjectID + * @param \Illuminate\Http\Request $request + * + * @return CourseYearQuarterCollection | \Illuminate\Http\JsonResponse **/ public function getCourseYearQuartersBySubject($yqrid, $subjectid, Request $request) { - if ( $request->input('format') === 'strm') { - //DB::connection('cs')->enableQueryLog(); - $cyqs = DB::connection('ods') - ->table('vw_Class') - ->where('STRM', '=', $yqrid) - ->where('Department', '=', $subjectid) - ->select('CourseID', 'Department', 'CourseNumber', 'YearQuarterID', 'STRM') - ->groupBy('CourseID', 'Department', 'CourseNumber', 'YearQuarterID', 'STRM') - ->orderBy('CourseNumber', 'asc') - ->get(); - - //$queries = DB::connection('cs')->getQueryLog(); - //dd($queries); - } else { - //DB::connection('cs')->enableQueryLog(); - $cyqs = DB::connection('ods') - ->table('vw_Class') - ->where('YearQuarterID', '=', $yqrid) + $validated = $request->validate([ + 'format' => 'sometimes|string|in:yrq,strm', + ]); + $selector = $request->input('format') === 'strm' ? 'STRM' : 'YearQuarterID'; + try { + $cyqs = CourseYearQuarter::where($selector, '=', $yqrid) ->where('Department', '=', $subjectid) - ->select('CourseID', 'Department', 'CourseNumber', 'YearQuarterID', 'STRM') - ->groupBy('CourseID', 'Department', 'CourseNumber', 'YearQuarterID', 'STRM') + ->distinctCourses() ->orderBy('CourseNumber', 'asc') ->get(); - - //$queries = DB::connection('cs')->getQueryLog(); - //dd($queries); + return new CourseYearQuarterCollection($cyqs); + } catch (\Exception $e) { + return response()->json(['classes' => []], 404); } - - - - - $data = $cyqs; - - if ( !is_null($cyqs) && !$cyqs->isEmpty() ) { - //When using the Eloquent query builder, we must "hydrate" the results back to collection of objects - $cyqs_hydrated = CourseYearQuarter::hydrate($cyqs->toArray()); - $collection = new Collection($cyqs_hydrated, new CourseYearQuarterTransformer, self::WRAPPER); - - //define serializer - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); - } - - return $this->respond($data); } } -?> diff --git a/app/Http/Controllers/EmployeeController.php b/app/Http/Controllers/EmployeeController.php index ddd8945..178d86e 100644 --- a/app/Http/Controllers/EmployeeController.php +++ b/app/Http/Controllers/EmployeeController.php @@ -3,256 +3,103 @@ namespace App\Http\Controllers; use App\Models\Employee; +use App\Http\Resources\EmployeeResource; + use App\Models\EmployeeDirectory; +use App\Http\Resources\EmployeeDirectoryDetailResource; +use App\Http\Resources\EmployeeDirectorySummaryCollection; + use App\Http\Controllers\ApiController; use Illuminate\Http\Request; -//use App\Exceptions\MissingParameterException; -use League\Fractal\Manager; -use League\Fractal\Resource\Item; -use League\Fractal\Resource\Collection; -use App\Http\Transformers\EmployeeTransformer; -use App\Http\Transformers\EmployeesTransformer; -use App\Http\Transformers\EmployeeDirectoryTransformer; -use App\Http\Serializers\CustomDataArraySerializer; -//use App\Http\Serializers\CustomDataArraySerializer; + use DB; class EmployeeController extends ApiController { - /** - * Get an employee by username - * Status: active - * - * @OA\Get( - * path="/api/v1/internal/employee/{username}", - * operationId="getEmployeeByUsername", - * tags={"Employees", "Internal"}, - * summary="Get employee information", - * description="Returns employee data", - * @OA\Parameter( - * name="username", - * description="Employee Username", - * required=true, - * in="path", - * @OA\Schema( - * type="string" - * ) - * ), - * @OA\Response( - * response=200, - * description="Successful operation", - * @OA\JsonContent(ref="#/components/schemas/Employee") - * ), - * @OA\Response( - * response=400, - * description="Bad Request" - * ), - * @OA\Response( - * response=401, - * description="Unauthenticated", - * ), - * @OA\Response( - * response=403, - * description="Forbidden" - * ), - * security={ - * {"jwtAuth": {"read:true"}} - * } - * ) - */ + * Get Employee by Username + * + * @param \Illuminate\Http\Request $request + * @param string $username Employee username + * + * @return EmployeeResource | stdClass + **/ public function getEmployeeByUsername(Request $request, $username) { - $emp = Employee::where('ADUserName', '=', $username)->where('EmployeeStatusCode', '=', 'A')->first(); - - $data = $emp; - //handle gracefully if null - if (! is_null($emp)) { - $item = new Item($emp, new EmployeeTransformer); - $fractal = new Manager; - $data = $fractal->createData($item)->toArray(); + try{ + // If username contains @, search UserPrincipal + if (strpos($username, '@') !== false) { + $emp = Employee::where('UserPrincipalName', '=', $username)->where('EmployeeStatusCode', '=', 'A')->firstOrFail(); + } else { + $emp = Employee::where('ADUserName', '=', $username)->where('EmployeeStatusCode', '=', 'A')->firstOrFail(); + } + return new EmployeeResource($emp); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); + } /** - * Get an employee by username from the directory - * Status: active - * - * @OA\Get( - * path="/api/v1/directory/employee/{username}", - * operationId="getDirectoryEmployeeByUsername", - * tags={"Employees", "Directory"}, - * summary="Get employee directory information", - * description="Returns employee directory data", - * @OA\Parameter( - * name="username", - * description="Employee Username", - * required=true, - * in="path", - * @OA\Schema( - * type="string" - * ) - * ), - * @OA\Response( - * response=200, - * description="Successful operation", - * @OA\JsonContent( - * @OA\Property( - * property="data", - * type="object", - * ref="#/components/schemas/DirectoryEmployee" - * ) - * ) - * ), - * @OA\Response( - * response=400, - * description="Bad Request" - * ), - * @OA\Response( - * response=401, - * description="Unauthenticated", - * ), - * @OA\Response( - * response=403, - * description="Forbidden" - * ), - * security={ - * {"jwtAuth": {"read:true"}} - * } - * ) - */ - + * Get Employee from Directory by Username + * + * Pass in the employee's username (e.g. "john.doe") as a parameter, and the employee's data will be returned. + * **Note**: This endpoint is authenticated, but available on the public API server. + * + * @param \Illuminate\Http\Request $request + * @param string $username Employee username + * + * @return EmployeeDirectoryDetailResource | stdClass + **/ public function getDirectoryEmployeeByUsername(Request $request, $username) { - - $emp = EmployeeDirectory::where('ADAccountName', '=', $username)->first(); - - - $data = $emp; - //handle gracefully if null - if (! is_null($emp)) { - $item = new Item($emp, new EmployeeDirectoryTransformer); - $fractal = new Manager; - $data = $fractal->createData($item)->toArray(); + try { + $emp = EmployeeDirectory::where('ADAccountName', '=', $username)->firstOrFail(); + return new EmployeeDirectoryDetailResource($emp); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); } /** - * Get a list of all directory employee usernames - * Status: active - * - * @OA\Get( - * path="/api/v1/directory/employees", - * operationId="getDirectoryEmployees", - * tags={"Employees", "Directory"}, - * summary="Get directory employee usernames", - * description="Returns a list of usernames of employees in the directory", - * @OA\Response( - * response=200, - * description="Successful operation", - * @OA\JsonContent( - * @OA\Property( - * property="employees", - * description="List of employees", - * type="array", - * @OA\Items( - * type="object", - * @OA\Property( - * property="username", - * type="string", - * description="Employee username", - * ), - * ), - * ), - * ), - * ), - * @OA\Response( - * response=400, - * description="Bad Request" - * ), - * @OA\Response( - * response=401, - * description="Unauthenticated", - * ), - * @OA\Response( - * response=403, - * description="Forbidden" - * ), - * security={ - * {"jwtAuth": {"read:true"}} - * } - * ) - */ + * Get all Employee usernames from the Directory + * + * **Note**: This endpoint is authenticated, but available on the public API server. + * + * @param \Illuminate\Http\Request $request + * + * @return EmployeeDirectorySummaryCollection | stdClass + **/ public function getDirectoryEmployees() { - $emps = EmployeeDirectory::whereNotNull('ADAccountName')->get(); - $collection = new Collection($emps, new EmployeesTransformer, 'employees'); - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); - return $this->respond($data); + try { + $emps = EmployeeDirectory::whereNotNull('ADAccountName')->get(); + return new EmployeeDirectorySummaryCollection($emps); + } catch (\Exception $e) { + return response()->json(new stdClass()); + } } - /* Additions by John begin */ /** - * Get a list of all directory employee usernames using substring search on DisplayName - * Status: active - * - * @OA\Get( - * path="/api/v1/directory/employeeDisplayNameSubstringSearch", - * operationId="getDirectoryEmployeeDisplayNameSubstringSearch", - * tags={"Employees", "Directory"}, - * summary="Get directory employee usernames by DisplayName substring search", - * description="Returns a list of usernames of employees in the directory by DisplayName substring search", - * @OA\Response( - * response=200, - * description="Successful operation", - * @OA\JsonContent( - * @OA\Property( - * property="employees", - * description="List of employees", - * type="array", - * @OA\Items( - * type="object", - * @OA\Property( - * property="username", - * type="string", - * description="Employee username", - * ), - * ), - * ), - * ), - * ), - * @OA\Response( - * response=400, - * description="Bad Request" - * ), - * @OA\Response( - * response=401, - * description="Unauthenticated", - * ), - * @OA\Response( - * response=403, - * description="Forbidden" - * ), - * security={ - * {"jwtAuth": {"read:true"}} - * } - * ) - */ + * Search for Directory Employees by DisplayName using substring search + * + * Pass in the employee's partial display name (e.g. "john") as a parameter, and matching employee data will be returned. + * + * **Note**: This endpoint is authenticated, but available on the public API server. + * + * @param \Illuminate\Http\Request $request + * @param string $username Employee username + * + * @return EmployeeDirectorySummaryCollection | stdClass + **/ public function getDirectoryEmployeeDisplayNameSubstringSearch(Request $request, $username) { - $emps = EmployeeDirectory::whereNotNull('ADAccountName')->where('DisplayName','like','%'.$username.'%')->get(); - $collection = new Collection($emps, new EmployeesTransformer, 'employees'); - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); - return $this->respond($data); + try { + $emps = EmployeeDirectory::whereNotNull('ADAccountName')->where('DisplayName','like','%'.$username.'%')->get(); + return new EmployeeDirectorySummaryCollection($emps); + } catch (\Exception $e) { + return response()->json(new stdClass()); + } } - /* Additions by John end */ } diff --git a/app/Http/Controllers/LinkFoundController.php b/app/Http/Controllers/LinkFoundController.php index 185979d..07d84ef 100644 --- a/app/Http/Controllers/LinkFoundController.php +++ b/app/Http/Controllers/LinkFoundController.php @@ -3,68 +3,51 @@ namespace App\Http\Controllers; use App\Models\LinkFound; -use App\Http\Transformers\LinkFoundTransformer; -use App\Http\Controllers\Controller; -use App\Http\Serializers\CustomDataArraySerializer; +use App\Http\Resources\LinkFoundCollection; use Illuminate\Http\Request; -use League\Fractal\Manager; -use League\Fractal\Resource\Collection; -use League\Fractal\Resource\Item; -use DB; +use Illuminate\Http\JsonResponse; class LinkFoundController extends ApiController { - - const WRAPPER = "Links"; - - /** - * Return all links - **/ - public function index(Manager $fractal, Request $request) + /** + * Return all links + * + * @return LinkFoundCollection + **/ + public function index(Request $request) { $links = LinkFound::all(); - $collection = new Collection($links, new LinkFoundTransformer); - - $fractal = new Manager; - $data = $fractal->createData($collection)->toArray(); - - return $this->respond($data); + return new LinkFoundCollection($links); } /** * Return links with descriptions based on a provided SourceArea value + * + * @param string $sourceArea SourceArea value + * + * @return LinkFoundCollection | JsonResponse **/ public function getLinksBySourceArea($sourceArea) { - $links = DB::connection('copilot') - ->table('vw_LinkFound') - ->where('SourceArea', '=', str_replace("+", " ",$sourceArea)) - ->select('LinkText', 'LinkDescr') - ->get(); - - $data = $links; - if (!is_null($links) && !$links->isEmpty()) { - //When using the Eloquent query builder, we must "hydrate" the results back to collection of objects - $links_hydrated = LinkFound::hydrate($links->toArray()); - $collection = new Collection($links_hydrated, new LinkFoundTransformer, self::WRAPPER); - - //set data serializer - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); + try { + $links = LinkFound::where('SourceArea', '=', str_replace("+", " ",$sourceArea)) + ->get(); + return new LinkFoundCollection($links); + } catch (\Exception $e) { + return response()->json(['Links' => []]); } - - return $this->respond($data); } /** * Return the count of links based on a provided SourceArea value + * + * @param string $sourceArea SourceArea value + * + * @return int **/ public function getLinkCountBySourceArea($sourceArea) { - $count = DB::connection('copilot') - ->table('vw_LinkFound') - ->where('SourceArea', '=', str_replace("+", " ",$sourceArea)) + $count = LinkFound::where('SourceArea', '=', str_replace("+", " ",$sourceArea)) ->count(); return $this->respond($count); diff --git a/app/Http/Controllers/StudentController.php b/app/Http/Controllers/StudentController.php index 0fd70bf..88be286 100644 --- a/app/Http/Controllers/StudentController.php +++ b/app/Http/Controllers/StudentController.php @@ -1,39 +1,37 @@ first(); - - $data = $stu; - - //handle gracefully if null - if ( !is_null($stu) ) { - $item = new Item($stu, new StudentTransformer); - - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - - $data = $fractal->createData($item)->toArray(); + try { + // If username contains @, search UserPrincipal + if (strpos($username, '@') !== false) { + $stu = Student::where('UserPrincipalName', '=', $username)->firstOrFail(); + } else { + $stu = Student::where('NTUserName', '=', $username)->firstOrFail(); + } + return new StudentResource($stu); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); } } diff --git a/app/Http/Controllers/SubjectController.php b/app/Http/Controllers/SubjectController.php index f5c219b..1335722 100644 --- a/app/Http/Controllers/SubjectController.php +++ b/app/Http/Controllers/SubjectController.php @@ -3,100 +3,67 @@ namespace App\Http\Controllers; use App\Models\Subject; -use App\Models\SubjectPrefix; -use App\Http\Transformers\SubjectTransformer; +use App\Http\Resources\SubjectResource; +use App\Http\Resources\SubjectCollection; use App\Http\Controllers\Controller; -use App\Http\Serializers\CustomDataArraySerializer; use Illuminate\Http\Request; -use League\Fractal\Manager; -use League\Fractal\Resource\Collection; -use League\Fractal\Resource\Item; use DB; +use stdClass; class SubjectController extends ApiController { - const WRAPPER = "subjects"; - - /** - * Return all subjects - **/ - public function index(Manager $fractal, Request $request) - { - if ($request->input('filter') === 'active-credit') { - $subjects = Subject:: - where('DESCR', 'not like', 'CE%') - ->where('DESCR', 'not like', '% (Inactive)') - ->orderBy('SUBJECT', 'ASC') - ->get(); - } else { - $subjects = Subject:: - orderBy('SUBJECT', 'ASC') - ->get(); - } - $data = $subjects; - if (!is_null($subjects)) { - $collection = new Collection($subjects, new SubjectTransformer, self::WRAPPER); - - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); - } - - return $this->respond($data); - } - /** - * Return a subject based on a provided slug + * List all Subjects + * + * @param Request $request + + * @return SubjectCollection | stdClass **/ - public function getSubject($slug) + public function index(Request $request) { + try { + if ($request->input('filter') === 'active-credit') { + $subjects = Subject:: + where('DESCR', 'not like', 'CE%') + ->where('DESCR', 'not like', '% (Inactive)') + ->orderBy('SUBJECT', 'ASC') + ->get(); + } else { + $subjects = Subject:: + orderBy('SUBJECT', 'ASC') + ->get(); + } - $subject = Subject::where('SUBJECT', '=', $slug)->first(); - - $data = $subject; - //handle gracefully if null - if (!is_null($subject)) { - $item = new Item($subject, new SubjectTransformer, "subject"); - - $fractal = new Manager; - - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($item)->toArray(); + return new SubjectCollection($subjects); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); } /** - * Return subjects based on a provided YearQuarterID + * Return Subject by Slug + * + * @param string $slug Subject slug + * + * @response array{subject: array{subject: string, name: string}} + * + * @return \Illuminate\Http\JsonResponse **/ - public function getSubjectsByYearQuarter($yqr) + public function getSubject($slug) { - - //DB::connection('cs')->enableQueryLog(); - $subjects = DB::connection('ods') - ->table('vw_PSSubject') - ->join('vw_Class', 'vw_PSSubject.SUBJECT', '=', 'vw_Class.Department') - ->where('vw_Class.YearQuarterID', '=', $yqr) - ->select('vw_PSSubject.SUBJECT', 'vw_PSSubject.DESCR as DESCR') - ->groupBy('vw_PSSubject.SUBJECT', 'vw_PSSubject.DESCR') - ->orderBy('vw_PSSubject.SUBJECT', 'asc') - ->get(); - //$queries = DB::connection('cs')->getQueryLog(); - //dd($queries); - - $data = $subjects; - if (!is_null($subjects) && !$subjects->isEmpty()) { - //When using the Eloquent query builder, we must "hydrate" the results back to collection of objects - $subjects_hydrated = Subject::hydrate($subjects->toArray()); - $collection = new Collection($subjects_hydrated, new SubjectTransformer, self::WRAPPER); - - //set data serializer - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); + try { + $subject = Subject::where('SUBJECT', '=', $slug)->firstOrFail(); + // We're wrapping in a subject array to match the response format + // Normal wrapping methods don't work because of double 'subject' + // in both the wrapper and the resource. + // This also requires the response to be manually listed in the + // docblock to ensure documentation is correct. + return response()->json([ + 'subject' => new SubjectResource($subject) + ]); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); } } diff --git a/app/Http/Controllers/YearQuarterController.php b/app/Http/Controllers/YearQuarterController.php index 6231979..9a577ba 100644 --- a/app/Http/Controllers/YearQuarterController.php +++ b/app/Http/Controllers/YearQuarterController.php @@ -3,144 +3,123 @@ namespace App\Http\Controllers; use App\Models\YearQuarter; -use App\Http\Transformers\YearQuarterTransformer; +use App\Http\Resources\YearQuarterResource; +use App\Http\Resources\YearQuarterCollection; use App\Http\Controllers\Controller; -use App\Http\Serializers\CustomDataArraySerializer; use Illuminate\Http\Request; -use League\Fractal\Manager; -use League\Fractal\Resource\Collection; -use League\Fractal\Resource\Item; -use DB; +use Carbon\Carbon; +use stdClass; class YearQuarterController extends ApiController { - const WRAPPER = "quarters"; - /** - * Return all YearQuarters + * List all Terms (YearQuarters) * Status: inactive * No active route. No set serialization. + * + * @return YearQuarterCollection | stdClass **/ - public function index(){ - - $yqrs = YearQuarter::all(); - $collection = new Collection($yqrs, new YearQuarterTransformer); - - $fractal = new Manager; - $data = $fractal->createData($collection)->toArray(); - - return $this->respond($data); - + public function index() + { + try { + $yqrs = YearQuarter::all(); + return new YearQuarterCollection($yqrs); + } catch (\Exception $e) { + return response()->json(new stdClass()); + } } /** - * Get YearQuarter based on a given YearQuarterID or STRM + * Get Term (YearQuarter) by YearQuarterID or STRM + * + * use ?format=strm or ?format=yrq to specify which format to return * - * use ?format=strm or ?format=yrq + * @param string $yqrid YearQuarterID or STRM + * @param \Illuminate\Http\Request $request + * + * @response array{quarter: array{quarter: string, strm: string, title: string}} + * + * @return \Illuminate\Http\JsonResponse | stdClass **/ public function getYearQuarter($yqrid, Request $request){ - if ( $request->input('format') === 'strm') { - $yqr = YearQuarter::where('STRM', '=', $yqrid)->first(); - } else { - $yqr = YearQuarter::where('YearQuarterID', '=', $yqrid)->first(); - } - - $data = $yqr; - //only serialize if not empty - if ( !is_null($yqr) ) { - $item = new Item($yqr, new YearQuarterTransformer, "quarter"); - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($item)->toArray(); + try { + if ( $request->input('format') === 'strm') { + $yqr = YearQuarter::where('STRM', '=', $yqrid)->firstOrFail(); + } else { + $yqr = YearQuarter::where('YearQuarterID', '=', $yqrid)->firstOrFail(); + } + // We're wrapping in a quarter array to match the response format + // Normal wrapping methods don't work because of double 'quarter' + // in both the wrapper and the resource. + // This also requires the response to be manually listed in the + // docblock to ensure documentation is correct. + return response()->json([ + 'quarter' => new YearQuarterResource($yqr) + ]); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); } /** - * Get current YearQuarter + * Get Current Term (YearQuarter) + * + * @response array{quarter: array{quarter: string, strm: string, title: string}} + + * @return \Illuminate\Http\JsonResponse **/ public function getCurrentYearQuarter() { - $yqr = YearQuarter::current()->first(); - - $data = $yqr; - //only serialize if not empty - if (!is_null($yqr)) { - $item = new Item($yqr, new YearQuarterTransformer, "quarter"); - - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($item)->toArray(); + try { + $yqr = YearQuarter::current()->firstOrFail(); + // We're wrapping in a quarter array to match the response format + // Normal wrapping methods don't work because of double 'quarter' + // in both the wrapper and the resource. + // This also requires the response to be manually listed in the + // docblock to ensure documentation is correct. + return response()->json([ + 'quarter' => new YearQuarterResource($yqr) + ]); + } catch (\Exception $e) { + return response()->json(new stdClass()); } - - return $this->respond($data); } /** - * Returns "active" YearQuarters + * List Active Terms (YearQuarters) + * + * @return YearQuarterCollection | stdClass **/ public function getViewableYearQuarters() { - //get max quarters to be shown - $max_yqr = config('dataapi.yearquarter_maxactive'); - $lookahead = config('dataapi.yearquarter_lookahead'); - $timezone = new \DateTimeZone(config("dataapi.timezone")); - - //Create now date/time object - $now = new \DateTime(); - $now->setTimezone($timezone); - $now_string = $now->format("Y-m-d H:i:s"); - - //Create lookahead date - $la_date = $now->add(new \DateInterval('P'.$lookahead.'D')); - $la_string = $la_date->format("Y-m-d H:i:s"); - - //Use Eloquent query builder to query results - //DB::connection('ods')->enableQueryLog(); - $yqrs = DB::connection('ods') - ->table('vw_YearQuarter') - ->join('vw_WebRegistrationSetting', 'vw_WebRegistrationSetting.YearQuarterID', '=', 'vw_YearQuarter.YearQuarterID') - ->where(function ($query) { - $lookahead = config('dataapi.yearquarter_lookahead'); - $timezone = new \DateTimeZone(config("dataapi.timezone")); - - //Create now date/time object - $now = new \DateTime(); - $now->setTimezone($timezone); - $now_string = $now->format("Y-m-d H:i:s"); - - //Create lookahead date - $la_date = $now->add(new \DateInterval('P'.$lookahead.'D')); - $la_string = $la_date->format("Y-m-d H:i:s"); - - $query->whereNotNull('vw_WebRegistrationSetting.FirstRegistrationDate') - ->where('vw_WebRegistrationSetting.FirstRegistrationDate', '<=', $la_string ) - ->orWhere('vw_YearQuarter.LastClassDay', '<=', $now_string ); - }) - ->select('vw_YearQuarter.YearQuarterID', 'vw_YearQuarter.STRM', 'vw_YearQuarter.Title', 'vw_YearQuarter.FirstClassDay', 'vw_YearQuarter.LastClassDay', 'vw_YearQuarter.AcademicYear') - ->orderBy('vw_YearQuarter.FirstClassDay', 'desc') - ->take($max_yqr) - ->get(); - //$queries = DB::connection('ods')->getQueryLog(); - //dd($queries); - //var_dump($yqrs); - - //When using the Eloquent query builder, we must "hydrate" the results back to collection of objects - $data = $yqrs; - - if ( !empty($yqrs) && !$yqrs->isEmpty() ) { - $yqr_hydrated = YearQuarter::hydrate($yqrs->toArray()); - $collection = new Collection($yqr_hydrated, new YearQuarterTransformer, self::WRAPPER); - - //Set data serializer - $fractal = new Manager; - $fractal->setSerializer(new CustomDataArraySerializer); - $data = $fractal->createData($collection)->toArray(); - } - - return $this->respond($data); + try { + // get max quarters to be shown + $max_yqr = config('dataapi.yearquarter_maxactive'); + + // get max days to look ahead + $lookaheadDays = config('dataapi.yearquarter_lookahead'); + + //Create now date/time object and lookahead date + $now = Carbon::now(); + $lookahead = Carbon::now()->addDays($lookaheadDays); + + // get active year quarters based on registration settings + // ideally this should move to the model in the future + $yrqs = YearQuarter::whereHas('webRegistrationSetting') + ->where(function($query) use ($lookahead, $now) { + $query->whereHas('webRegistrationSetting', function ($q) use ($lookahead) { + $q->whereNotNull('FirstRegistrationDate') + ->where('FirstRegistrationDate', '<=', $lookahead); + }) + ->orWhere('LastClassDay', '<=', $now); + }) + ->orderBy('FirstClassDay', 'desc') + ->take($max_yqr) + ->get(); + return new YearQuarterCollection($yrqs); + } catch (\Exception $e) { + return response()->json(new stdClass()); + } } } -?> diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index e5b33c6..6a5713d 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -53,6 +53,7 @@ class Kernel extends HttpKernel protected $middlewareAliases = [ 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'guard.api-basic' => \App\Http\Middleware\SetApiBasicGuard::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, diff --git a/app/Http/Middleware/SetApiBasicGuard.php b/app/Http/Middleware/SetApiBasicGuard.php new file mode 100644 index 0000000..5a3db32 --- /dev/null +++ b/app/Http/Middleware/SetApiBasicGuard.php @@ -0,0 +1,18 @@ + + */ + public function toArray(Request $request): array + { + return [ + /** @var string Access token */ + 'access_token' => $this->resource['access_token'], + 'token_type' => 'bearer', + /** @var int Time in seconds until token expires */ + 'expires_in' => $this->resource['expires_in'] + ]; + } +} diff --git a/app/Http/Resources/ClassScheduleCollection.php b/app/Http/Resources/ClassScheduleCollection.php new file mode 100644 index 0000000..fa9c4ab --- /dev/null +++ b/app/Http/Resources/ClassScheduleCollection.php @@ -0,0 +1,23 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Http/Resources/ClassScheduleResource.php b/app/Http/Resources/ClassScheduleResource.php new file mode 100644 index 0000000..1942ed0 --- /dev/null +++ b/app/Http/Resources/ClassScheduleResource.php @@ -0,0 +1,36 @@ + + */ + public function toArray(Request $request): array + { + $days = trim($this->DayID); + if ($days == "ARR") + $days = "To be arranged"; + elseif ($days == "DALY") + $days = "Daily"; + elseif ($days != "") { + $days = str_replace("U","Su",$days); + $days = str_replace("R","Th",$days); + } + return [ + 'days' => $days, + 'room' => $this->location, + 'roomDescription' => $this->RoomDescr, + 'instructor' => $this->InstructorName, + 'beginDate' => $this->getFormattedDate($this->StartDate), + 'endDate' => $this->getFormattedDate($this->EndDate), + 'schedule' => trim($this->schedule), + ]; + } +} diff --git a/app/Http/Resources/CourseCollection.php b/app/Http/Resources/CourseCollection.php new file mode 100644 index 0000000..63950d1 --- /dev/null +++ b/app/Http/Resources/CourseCollection.php @@ -0,0 +1,24 @@ + + */ + public function toArray(Request $request): array + { + return $this->collection->toArray(); + } +} diff --git a/app/Http/Resources/CourseResource.php b/app/Http/Resources/CourseResource.php new file mode 100644 index 0000000..94de8e5 --- /dev/null +++ b/app/Http/Resources/CourseResource.php @@ -0,0 +1,43 @@ + + */ + public function toArray(Request $request): array + { + //filter to get the active course description + $all_desc = $this->coursedescriptions(); + $cd_desc = null; + + if (!is_null($all_desc)) { + $cd_active = $all_desc->activedescription()->first(); + + if (!empty($cd_active)) { + $cd_desc = utf8_encode($cd_active->Description); + } + } + + return [ + 'title' => $this->title, + 'subject' => $this->CourseSubject, + 'courseNumber' => $this->CatalogNumber, + 'courseId' => $this->CourseID, + 'ctcCourseId' => $this->PSCourseID, + 'description' => $cd_desc, + 'note' => $this->note, + 'credits' => $this->Credits, + 'isVariableCredits' => (bool)$this->VariableCredits, + 'isCommonCourse' => (bool)$this->isCommonCourse, + ]; + } +} diff --git a/app/Http/Resources/CourseYearQuarterCollection.php b/app/Http/Resources/CourseYearQuarterCollection.php new file mode 100644 index 0000000..f566f67 --- /dev/null +++ b/app/Http/Resources/CourseYearQuarterCollection.php @@ -0,0 +1,23 @@ + + */ + public function toArray(Request $request): array + { + return $this->collection->toArray(); + } +} diff --git a/app/Http/Resources/CourseYearQuarterResource.php b/app/Http/Resources/CourseYearQuarterResource.php new file mode 100644 index 0000000..0229141 --- /dev/null +++ b/app/Http/Resources/CourseYearQuarterResource.php @@ -0,0 +1,49 @@ + + */ + public function toArray($request) + { + // Get the course description logic from the transformer + $description = null; + $course = $this->course; + if ($course) { + $allDesc = $course->coursedescriptions(); + if ($allDesc) { + $activeDesc = $allDesc->activedescription($this->YearQuarterID)->first(); + if ($activeDesc) { + $description = utf8_encode($activeDesc->Description); + } + } + } + + return [ + 'title' => $this->title, + 'subject' => trim($this->Department), + 'courseNumber' => trim($this->CourseNumber), + 'description' => $description, + 'note' => $course->note ?? $this->note ?? null, + /** @var int */ + 'credits' => $this->course->Credits, + 'quarter' => $this->YearQuarterID, + 'strm' => $this->STRM, + 'isVariableCredits' => (bool)$course->isVariableCredits, + 'isCommonCourse' => (bool)$course->isCommonCourse, + 'sections' => [ 'data' => + new SectionCollection($this->sections), + ], + ]; + } +} diff --git a/app/Http/Resources/EmployeeDirectoryDetailResource.php b/app/Http/Resources/EmployeeDirectoryDetailResource.php new file mode 100644 index 0000000..6b833cb --- /dev/null +++ b/app/Http/Resources/EmployeeDirectoryDetailResource.php @@ -0,0 +1,40 @@ + + */ + public function toArray(Request $request): array + { + $title = $this->WorkingTitle !== NULL ? $this->WorkingTitle : $this->OfficialTitle; + + // Remove whitespace and control characters + $title = preg_replace('/[\x00-\x1F\x7F\xA0]/u', ' ', $title); + + return [ + 'firstName' => $this->FirstName, + 'lastName' => $this->LastName, + /** @var string|null Alias/Nickname */ + 'aliasName' => $this->AKA, + 'displayName' => $this->DisplayName, + /** @var string|null Title */ + 'title' => $title, + 'department' => $this->DepartmentName, + 'email' => $this->BCCEmail, + 'phone' => $this->WorkPhone, + 'displayPhone' => $this->DisplayPhone, + 'office' => $this->WorkOffice, + 'mailstop' => $this->MailStop, + ]; + } +} diff --git a/app/Http/Resources/EmployeeDirectorySummaryCollection.php b/app/Http/Resources/EmployeeDirectorySummaryCollection.php new file mode 100644 index 0000000..5817d78 --- /dev/null +++ b/app/Http/Resources/EmployeeDirectorySummaryCollection.php @@ -0,0 +1,34 @@ + + */ + public function toArray(Request $request): array + { + return $this->collection->toArray(); + } +} diff --git a/app/Http/Resources/EmployeeDirectorySummaryResource.php b/app/Http/Resources/EmployeeDirectorySummaryResource.php new file mode 100644 index 0000000..1fe6fb5 --- /dev/null +++ b/app/Http/Resources/EmployeeDirectorySummaryResource.php @@ -0,0 +1,22 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'username' => $this->ADAccountName, + ]; + } +} diff --git a/app/Http/Resources/EmployeeResource.php b/app/Http/Resources/EmployeeResource.php new file mode 100644 index 0000000..4a85682 --- /dev/null +++ b/app/Http/Resources/EmployeeResource.php @@ -0,0 +1,30 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'SID' => $this->SID, + 'EMPLID' => $this->EMPLID, + 'AzureID' => $this->AzureID, + 'firstName' => $this->FirstName, + 'lastName' => $this->LastName, + 'aliasName' => $this->AliasName, + 'email' => $this->WorkEmail, + 'phone' => $this->WorkPhoneNumber, + 'username' => $this->ADUserName, + 'UPN' => $this->UserPrincipalName, + ]; + } +} diff --git a/app/Http/Resources/LinkFoundCollection.php b/app/Http/Resources/LinkFoundCollection.php new file mode 100644 index 0000000..d6cb941 --- /dev/null +++ b/app/Http/Resources/LinkFoundCollection.php @@ -0,0 +1,22 @@ + + */ + public function toArray(Request $request): array + { + return $this->collection->toArray(); + } +} diff --git a/app/Http/Resources/LinkFoundResource.php b/app/Http/Resources/LinkFoundResource.php new file mode 100644 index 0000000..a369f37 --- /dev/null +++ b/app/Http/Resources/LinkFoundResource.php @@ -0,0 +1,23 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'Link' => $this->LinkText, + 'Description' => $this->LinkDescr, + ]; + } +} diff --git a/app/Http/Resources/SectionCollection.php b/app/Http/Resources/SectionCollection.php new file mode 100644 index 0000000..a19a92d --- /dev/null +++ b/app/Http/Resources/SectionCollection.php @@ -0,0 +1,22 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Http/Resources/SectionResource.php b/app/Http/Resources/SectionResource.php new file mode 100644 index 0000000..60f21d4 --- /dev/null +++ b/app/Http/Resources/SectionResource.php @@ -0,0 +1,43 @@ + + */ + public function toArray(Request $request): array + { + /** + * Get asssociated days + */ + $days = trim($this->DayID); + if ($days == "ARR") + $days = "To be arranged"; + elseif ($days == "DALY") + $days = "Daily"; + elseif ($days != "") { + $days = str_replace("U","Su",$days); + $days = str_replace("R","Th",$days); + } + return [ + 'id' => $this->ClassID, + 'section' => $this->Section, + 'itemNumber' => $this->ItemNumber, + 'classNumber' => $this->ClassNumber, + 'instructor' => $this->InstructorName, + 'beginDate' => $this->getFormattedDate($this->StartDate), + 'endDate' => $this->getFormattedDate($this->EndDate), + 'room' => $this->location, + 'days' => $days, + 'schedule' => trim($this->schedule), + 'roomDescription' => $this->RoomDescr, + ]; + } +} diff --git a/app/Http/Resources/StudentResource.php b/app/Http/Resources/StudentResource.php new file mode 100644 index 0000000..6b2f879 --- /dev/null +++ b/app/Http/Resources/StudentResource.php @@ -0,0 +1,31 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'SID' => $this->SID, + 'EMPLID' => $this->EMPLID, + 'AzureID' => $this->AzureID, + 'firstName' => $this->FirstName, + 'lastName' => $this->LastName, + 'email' => $this->Email, + 'phoneDaytime' => $this->DaytimePhone, + 'phoneEvening' => $this->EveningPhone, + 'username' => $this->NTUserName, + 'UPN' => $this->UserPrincipalName, + 'ferpaBlock' => $this->PrivateRecord, + ]; + } +} diff --git a/app/Http/Resources/SubjectCollection.php b/app/Http/Resources/SubjectCollection.php new file mode 100644 index 0000000..49d142a --- /dev/null +++ b/app/Http/Resources/SubjectCollection.php @@ -0,0 +1,24 @@ + + */ + public function toArray(Request $request): array + { + return $this->collection->toArray(); + } +} diff --git a/app/Http/Resources/SubjectResource.php b/app/Http/Resources/SubjectResource.php new file mode 100644 index 0000000..1800558 --- /dev/null +++ b/app/Http/Resources/SubjectResource.php @@ -0,0 +1,22 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'subject' => $this->SUBJECT, + 'name' => $this->DESCR, + ]; + } +} diff --git a/app/Http/Resources/YearQuarterCollection.php b/app/Http/Resources/YearQuarterCollection.php new file mode 100644 index 0000000..7ac6749 --- /dev/null +++ b/app/Http/Resources/YearQuarterCollection.php @@ -0,0 +1,21 @@ + + */ + public function toArray(Request $request): array + { + return $this->collection->toArray(); + } +} diff --git a/app/Http/Resources/YearQuarterResource.php b/app/Http/Resources/YearQuarterResource.php new file mode 100644 index 0000000..5d2f602 --- /dev/null +++ b/app/Http/Resources/YearQuarterResource.php @@ -0,0 +1,23 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'quarter' => $this->YearQuarterID, + 'strm' => $this->STRM, + 'title' => $this->Title, + ]; + } +} diff --git a/app/Http/Serializers/CustomDataArraySerializer.php b/app/Http/Serializers/CustomDataArraySerializer.php deleted file mode 100644 index 6ba6e25..0000000 --- a/app/Http/Serializers/CustomDataArraySerializer.php +++ /dev/null @@ -1,54 +0,0 @@ - $data); - } - - /** - * Serialize an item. - * - * @param string $resourceKey - * @param array $data - * - * @return array - */ - public function item(?string $resourceKey, array $data):array - { - if ($resourceKey === false) { - return $data; - } - return array($resourceKey ?: 'data' => $data); - } - - /** - * Serialize null resource. - * - * @return array - */ - public function null():?array - { - return null; - } -} diff --git a/app/Http/Transformers/ClassScheduleTransformer.php b/app/Http/Transformers/ClassScheduleTransformer.php deleted file mode 100644 index 1583e76..0000000 --- a/app/Http/Transformers/ClassScheduleTransformer.php +++ /dev/null @@ -1,40 +0,0 @@ -DayID); - if ($days == "ARR") - $days = "To be arranged"; - elseif ($days == "DALY") - $days = "Daily"; - elseif ($days != "") { - $days = str_replace("U","Su",$days); - $days = str_replace("R","Th",$days); - } - - return [ - 'days' => $days, - 'room' => $sch->location, - 'roomDescription' => $sch->RoomDescr, - 'instructor' => $sch->InstructorName, - 'beginDate' => $sch->getFormattedDate($sch->StartDate), - 'endDate' => $sch->getFormattedDate($sch->EndDate), - 'schedule' => trim($sch->schedule), - ]; - } -} diff --git a/app/Http/Transformers/CourseTransformer.php b/app/Http/Transformers/CourseTransformer.php deleted file mode 100644 index 60166e0..0000000 --- a/app/Http/Transformers/CourseTransformer.php +++ /dev/null @@ -1,45 +0,0 @@ -coursedescriptions(); - $cd_desc = null; - - if (!is_null($all_desc)) { - $cd_active = $all_desc->activedescription()->first(); - - if (!empty($cd_active)) { - $cd_desc = utf8_encode($cd_active->Description); - } - } - - - return [ - 'title' => $course->title, - 'subject' => $course->CourseSubject, - 'courseNumber' => $course->CatalogNumber, - 'courseId' => $course->CourseID, - 'ctcCourseId' => $course->PSCourseID, - 'description' => $cd_desc, - 'note' => $course->note, - 'credits' => $course->Credits, - 'isVariableCredits' => (bool)$course->VariableCredits, - 'isCommonCourse' => $course->isCommonCourse, - ]; - } -} diff --git a/app/Http/Transformers/CourseYearQuarterTransformer.php b/app/Http/Transformers/CourseYearQuarterTransformer.php deleted file mode 100644 index 4fb0486..0000000 --- a/app/Http/Transformers/CourseYearQuarterTransformer.php +++ /dev/null @@ -1,71 +0,0 @@ -course->coursedescriptions(); - $cd_desc = null; - if ( !is_null($all_desc) ) - { - $cd_active = $all_desc->activedescription($cyq->YearQuarterID)->first(); - - if ( !empty($cd_active) ) { - $cd_desc = utf8_encode($cd_active->Description); - } - } - - return [ - 'title' => $cyq->title, - 'subject' => trim($cyq->Department), - 'courseNumber' => trim($cyq->CourseNumber), - 'description' => $cd_desc, - 'note' => $cyq->course->note, - 'credits' => $cyq->course->Credits, - 'quarter' => $cyq->YearQuarterID, - 'strm' => $cyq->STRM, - 'isVariableCredits' => (bool)$cyq->course->VariableCredits, - 'isCommonCourse' => $cyq->course->isCommonCourse, - ]; - } - - /** - * Include sections for class - * - * @return League\Fractal\Resource\Collection - */ - public function includeSections(CourseYearQuarter $cyq) - { - $sections = $cyq->getSectionsAttribute(); - - if ( $sections->count() == 0) { - //return null resource - return $this->null(); - } - //set resource key as false so data isn't "double wrapped" with a section identifier - $sections_transformed = $this->collection($sections, new SectionTransformer, false); - - return $sections_transformed; - } - -} diff --git a/app/Http/Transformers/EmployeeDirectoryTransformer.php b/app/Http/Transformers/EmployeeDirectoryTransformer.php deleted file mode 100644 index 2f00538..0000000 --- a/app/Http/Transformers/EmployeeDirectoryTransformer.php +++ /dev/null @@ -1,36 +0,0 @@ -WorkingTitle !== NULL ? $emp->WorkingTitle : $emp->OfficialTitle; - - // Remove Whitespace and control characters - $title = preg_replace('/[\x00-\x1F\x7F\xA0]/u', ' ', $title); - - return [ - 'firstName' => $emp->FirstName, - 'lastName' => $emp->LastName, - 'aliasName' => $emp->AKA, - 'displayName' => $emp->DisplayName, - 'title' => $title, - 'department' => $emp->DepartmentName, - 'email' => $emp->BCCEmail, - 'phone' => $emp->WorkPhone, - 'displayPhone' => $emp->DisplayPhone, - 'office' => $emp->WorkOffice, - 'mailstop' => $emp->MailStop, - ]; - } - -} diff --git a/app/Http/Transformers/EmployeeTransformer.php b/app/Http/Transformers/EmployeeTransformer.php deleted file mode 100644 index b862b3f..0000000 --- a/app/Http/Transformers/EmployeeTransformer.php +++ /dev/null @@ -1,28 +0,0 @@ - $emp->SID, - 'EMPLID' => $emp->EMPLID, - 'firstName' => $emp->FirstName, - 'lastName' => $emp->LastName, - 'aliasName' => $emp->AliasName, - 'email' => $emp->WorkEmail, - 'phone' => $emp->WorkPhoneNumber, - 'username' => $emp->ADUserName - ]; - } -} diff --git a/app/Http/Transformers/EmployeesTransformer.php b/app/Http/Transformers/EmployeesTransformer.php deleted file mode 100644 index f77c0af..0000000 --- a/app/Http/Transformers/EmployeesTransformer.php +++ /dev/null @@ -1,22 +0,0 @@ -WorkingTitle !== NULL ? $emp->WorkingTitle : $emp->OfficialTitle; - return [ - 'username' => $emp->ADAccountName, - ]; - } - -} diff --git a/app/Http/Transformers/LinkFoundTransformer.php b/app/Http/Transformers/LinkFoundTransformer.php deleted file mode 100644 index 934ce19..0000000 --- a/app/Http/Transformers/LinkFoundTransformer.php +++ /dev/null @@ -1,22 +0,0 @@ - $link->LinkText, - 'Description' => $link->LinkDescr, - ]; - } -} diff --git a/app/Http/Transformers/SectionTransformer.php b/app/Http/Transformers/SectionTransformer.php deleted file mode 100644 index a69d71f..0000000 --- a/app/Http/Transformers/SectionTransformer.php +++ /dev/null @@ -1,44 +0,0 @@ -DayID); - if ($days == "ARR") - $days = "To be arranged"; - elseif ($days == "DALY") - $days = "Daily"; - elseif ($days != "") { - $days = str_replace("U","Su",$days); - $days = str_replace("R","Th",$days); - } - - return [ - 'id' => $sec->ClassID, - 'section' => $sec->Section, - 'itemNumber' => $sec->ItemNumber, - 'classNumber' => $sec->ClassNumber, - 'instructor' => $sec->InstructorName, - 'beginDate' => $sec->getFormattedDate($sec->StartDate), - 'endDate' => $sec->getFormattedDate($sec->EndDate), - 'room' => $sec->location, - 'days' => $days, - 'schedule' => trim($sec->schedule), - 'roomDescription' => $sec->RoomDescr, - ]; - } -} diff --git a/app/Http/Transformers/StudentTransformer.php b/app/Http/Transformers/StudentTransformer.php deleted file mode 100644 index b566c0e..0000000 --- a/app/Http/Transformers/StudentTransformer.php +++ /dev/null @@ -1,30 +0,0 @@ - $stu->SID, - 'EMPLID' => $stu->EMPLID, - 'firstName' => $stu->FirstName, - 'lastName' => $stu->LastName, - 'email' => $stu->Email, - 'phoneDaytime' => $stu->DaytimePhone, - 'phoneEvening' => $stu->EveningPhone, - 'username' => $stu->NTUserName, - 'ferpaBlock' => $stu->PrivateRecord, - ]; - } -} diff --git a/app/Http/Transformers/SubjectTransformer.php b/app/Http/Transformers/SubjectTransformer.php deleted file mode 100644 index b5ee5c8..0000000 --- a/app/Http/Transformers/SubjectTransformer.php +++ /dev/null @@ -1,22 +0,0 @@ - $sub->SUBJECT, - 'name' => $sub->DESCR, - ]; - } -} diff --git a/app/Http/Transformers/YearQuarterTransformer.php b/app/Http/Transformers/YearQuarterTransformer.php deleted file mode 100644 index ea84a66..0000000 --- a/app/Http/Transformers/YearQuarterTransformer.php +++ /dev/null @@ -1,23 +0,0 @@ - $yqr->YearQuarterID, - 'strm' => $yqr->STRM, - 'title' => $yqr->Title - ]; - } - -} diff --git a/app/Models/Client.php b/app/Models/Client.php index 3b30e1c..2ee6943 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -12,6 +12,9 @@ class Client extends Authenticatable implements JWTSubject { protected $connection = 'da'; protected $fillable = ['id', 'clientname', 'clientid', 'clienturl']; protected $hidden = ['created_at', 'updated_at', 'password']; + protected $casts = [ + 'permissions' => 'array', + ]; /** * Get the identifier that will be stored in the subject claim of the JWT. @@ -41,4 +44,24 @@ public static function generateClientKey() { return (string) Str::uuid(); } + + /** + * Sync client permissions by permission names + * + * @param array $permissionNames Array of permission names to sync + * @return array + */ + public function syncPermissionsByName(array $permissionNames) + { + $this->permissions = $permissionNames; + $this->save(); + } + + /** + * Check if client has a specific permission + */ + public function hasPermission($permissionName) + { + return in_array($permissionName, $this->permissions ?? []); + } } \ No newline at end of file diff --git a/app/Models/Course.php b/app/Models/Course.php index 911dee9..0e13029 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -88,4 +88,11 @@ public function scopeActiveAsOfYearQuarter($query, $yqrid) ->orWhereNull('EffectiveYearQuarterEnd'); }); } + + /** Scope to filter out transfer-in courses */ + public function scopeNotTransferIn($query) + { + return $query->where('CourseTitle2', '<>', 'Transfer In Course') + ->where('CourseTitle', '<>', 'Transferred-In Course'); + } } diff --git a/app/Models/CourseYearQuarter.php b/app/Models/CourseYearQuarter.php index b6d41c9..4adecf0 100644 --- a/app/Models/CourseYearQuarter.php +++ b/app/Models/CourseYearQuarter.php @@ -2,54 +2,67 @@ use App\Models\Section; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Builder; use DB; + + class CourseYearQuarter extends Model { + // Allow for relationships based on composite keys + use \Awobaz\Compoships\Compoships; + /** * We can't use the name Class since it's a reserved word, so CourseYearQuarter to * represent a class (course offered in a year quarter) it is. This is NOT the same * as a section. * Relationship: A Course is offered in a YearQuarter (CourseYearQuarter), those year quarter offerings have Sections. **/ - protected $table = 'vw_Class'; - protected $connection = 'ods'; - protected $primaryKey = null; - public $timestamps = false; - - - public function course() { - //scope relationship to retrieve only course relevant to YearQuarter of this CourseYearQuarter - return $this->belongsTo('App\Models\Course', 'CourseID', 'CourseID')->activeasofyearquarter($this->YearQuarterID); - } - - /** - * Section is a child model of CourseYearQuarter - * Because of the data organization/definitions, we can't use standard relationship definitions (see course) - * so I made this accessor version instead. It will return the expected collection of child Section objects. + protected $table = 'vw_Class'; + protected $connection = 'ods'; + protected $primaryKey = null; + public $timestamps = false; + + + public function course() { + //scope relationship to retrieve only course relevant to YearQuarter of this CourseYearQuarter + return $this->belongsTo('App\Models\Course', 'CourseID', 'CourseID')->activeasofyearquarter($this->YearQuarterID); + } + + /** + * Set relationship for sections (use Compoships to handle composite keys) **/ - public function getSectionsAttribute() { + public function sections() { + return $this->hasMany( + Section::class, + ['YearQuarterID', 'Department', 'CourseNumber'], + ['YearQuarterID', 'Department', 'CourseNumber'] + ); + } - //Sections are children of CourseYearQuarter - $sections = Section::where('YearQuarterID', '=', $this->YearQuarterID) - ->where('Department', '=', $this->Department) - ->where('CourseNumber', '=', $this->CourseNumber) - ->get(); - - return $sections; - } - - /** + /** * Accessor that wraps logic around which course title should be returned **/ - public function getTitleAttribute() { - $title = $this->course->title; + public function getTitleAttribute() { + $title = $this->course->title; - if ( is_null($title) ) { - //if parent course title is null, default to CourseYearQuarter title - $title = $this->CourseTitle; + if ( is_null($title) ) { + //if parent course title is null, default to CourseYearQuarter title + $title = $this->CourseTitle; } return $title; - } + } + + /** + * Scope to only return distinct courses + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @return void + */ + public function scopeDistinctCourses(Builder $query) + { + // previously was ->groupBy('CourseID', 'Department', 'CourseNumber', 'YearQuarterID', 'STRM') + $query->select('CourseID', 'Department', 'CourseNumber', 'YearQuarterID', 'STRM')->distinct(); + } } ?> \ No newline at end of file diff --git a/app/Models/EmployeeDirectory.php b/app/Models/EmployeeDirectory.php index c54656b..a601a97 100644 --- a/app/Models/EmployeeDirectory.php +++ b/app/Models/EmployeeDirectory.php @@ -11,7 +11,7 @@ class EmployeeDirectory extends Model //implements AuthenticatableContract, Auth //use Authenticatable, Authorizable; protected $connection = 'empdirectory'; protected $table = 'Employees'; - protected $primaryKey = 'SID'; + protected $primaryKey = 'EMPLID'; public $incrementing = false; public $timestamps = false; @@ -21,7 +21,7 @@ class EmployeeDirectory extends Model //implements AuthenticatableContract, Auth * @var array */ protected $hidden = [ - 'SID', + 'EMPLID', 'SearchField', 'SearchFieldDisplay', 'EmploymentDate', diff --git a/app/Models/Section.php b/app/Models/Section.php index caf1f55..cf8bde2 100644 --- a/app/Models/Section.php +++ b/app/Models/Section.php @@ -4,21 +4,23 @@ class Section extends Model { + // Allow for relationships based on composite keys + use \Awobaz\Compoships\Compoships; /** * Model for a section offered in a CourseYearQuarter. **/ - protected $table = 'vw_Class'; - protected $connection = 'ods'; - protected $primaryKey = 'PSClassID'; - public $incrementing = false; - public $timestamps = false; + protected $table = 'vw_Class'; + protected $connection = 'ods'; + protected $primaryKey = 'PSClassID'; + public $incrementing = false; + public $timestamps = false; - /** + /** * Defines child relationship for the section's schedule **/ - public function day() { - return $this->hasOne('App\Models\Day', 'DayID', 'DayID'); - } + public function day() { + return $this->hasOne('App\Models\Day', 'DayID', 'DayID'); + } /** * Defines child relationship for the section's schedules. @@ -28,22 +30,22 @@ public function classSchedules() : HasMany return $this->hasMany(classSchedule::class, 'PSClassID', 'PSClassID'); } - /** + /** * This accessor wraps some logic around the room/location for a class. **/ - public function getLocationAttribute() { - if ( $this->isOnlineSection() ) { - //can't have a room for an online section - return null; - } else { - return trim($this->Room); - } - } + public function getLocationAttribute() { + if ( $this->isOnlineSection() ) { + //can't have a room for an online section + return null; + } else { + return trim($this->Room); + } + } - /** + /** * This accessor wraps logic around the section schedule **/ - public function getScheduleAttribute() { + public function getScheduleAttribute() { $schedule = ""; if ( !is_null($this->StartTime) && !is_null($this->EndTime) ) { $st = new \DateTime($this->StartTime); @@ -54,33 +56,33 @@ public function getScheduleAttribute() { $schedule = $st_str . "-" . $et_str; } if ( $this->isOnlineSection() ) { - //online section so don't include day/time info - $schedule = "Online"; + //online section so don't include day/time info + $schedule = "Online"; } return $schedule; - } + } - /** + /** * Format a date to the format we want to use for section dates **/ - public function getFormattedDate($date) { + public function getFormattedDate($date) { $date_str = ""; if ( !is_null($date) ) { - $dateobj = new \DateTime($date); - $date_str = $dateobj->format("m-d-Y"); + $dateobj = new \DateTime($date); + $date_str = $dateobj->format("m-d-Y"); } return $date_str; - } + } - /** + /** * Logic to determine of section is an online section **/ - protected function isOnlineSection () { - if ( !empty($this->Section) && $this->Section == "OAS" ) { - return true; - } else { - return false; - } - } + protected function isOnlineSection () { + if ( !empty($this->Section) && $this->Section == "OAS" ) { + return true; + } else { + return false; + } + } } ?> diff --git a/app/Models/User.php b/app/Models/User.php index 3ac50b2..e0e8406 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -1,8 +1,6 @@ 'string', + 'FirstRegistrationDate' => 'datetime', + 'LastRegistrationDate' => 'datetime', + ]; + + /** + * Belongs to YearQuarter + */ + public function yearQuarter() + { + return $this->belongsTo(YearQuarter::class, 'STRM', 'STRM'); + } +} diff --git a/app/Models/YearQuarter.php b/app/Models/YearQuarter.php index 4a01da3..9771c31 100644 --- a/app/Models/YearQuarter.php +++ b/app/Models/YearQuarter.php @@ -1,5 +1,6 @@ - 'string', + 'FirstClassDay' => 'datetime', + 'LastClassDay' => 'datetime', ]; - protected $table = 'vw_YearQuarter'; - protected $connection = 'ods'; - protected $primaryKey = null; //Lumen will convert the YearQuarterID value to an integer if we make it aware of it - //protected $primaryKey = 'YearQuarterID'; + protected $table = 'vw_YearQuarter'; + protected $connection = 'ods'; + protected $primaryKey = null; - public function scopeCurrent($query) { + /** + * Has one WebRegistrationSetting + */ + public function webRegistrationSetting() + { + return $this->hasOne(WebRegistrationSetting::class, 'STRM', 'STRM'); + } + + public function scopeCurrent($query) { //Create now date/time object $timezone = new \DateTimeZone(config("app.timezone")); $now = new \DateTime(); @@ -29,4 +39,3 @@ public function scopeCurrent($query) { ->take(1); } } -?> diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 35471f6..68ae687 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,6 +3,11 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; +use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Event; +use App\Models\Client; +use Illuminate\Support\Facades\URL; +use Dedoc\Scramble\Scramble; class AppServiceProvider extends ServiceProvider { @@ -11,9 +16,65 @@ class AppServiceProvider extends ServiceProvider * * @return void */ - public function boot() + public function boot(): void { - // + // Fix URL generation for subdomain + subfolder deployments + $subdir = trim(parse_url(config('app.url'), PHP_URL_PATH) ?? '', '/'); + + if ($subdir !== '') { + // Use current request host, or APP_URL for CLI + URL::useOrigin( + app()->runningInConsole() + ? preg_replace('#(/.*)?$#', '', config('app.url')) + : request()->getSchemeAndHttpHost() + ); + + // Prefix all generated paths with subdirectory + URL::formatPathUsing(fn($path) => + str_starts_with($path = '/' . ltrim($path, '/'), "/$subdir/") || $path === "/$subdir" + ? $path + : ($path === '/' ? "/$subdir" : "/$subdir$path") + ); + } + // Fix Scramble's auto-generated internal domain servers + if (class_exists(Scramble::class)) { + $subdir = trim(parse_url(config('app.url'), PHP_URL_PATH) ?? '', '/'); + $internalDomain = config('dataapi.api_internal_domain'); + + if ($subdir && $internalDomain) { + Scramble::afterOpenApiGenerated(function ($openApi) use ($subdir, $internalDomain) { + $badUrl = "https://{$internalDomain}/api"; + $goodUrl = "https://{$internalDomain}/{$subdir}/api"; + + foreach ($openApi->paths as $pathItem) { + if (isset($pathItem->servers)) { + foreach ($pathItem->servers as $server) { + if ($server->url === $badUrl) { + $server->url = $goodUrl; + } + } + } + } + return $openApi; + }); + } + } + + /** + * Define Gates for each Permission + */ + foreach (config('permissions') as $permissionName => $permissionDescription) { + Gate::define($permissionName, function (Client $client) use ($permissionName) { + return $client->hasPermission($permissionName); + }); + } + + /** + * Set up Azure AD Socialite + */ + Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) { + $event->extendSocialite('azure', \SocialiteProviders\Azure\Provider::class); + }); } /** diff --git a/app/Scopes/AdminGroupScope.php b/app/Scopes/AdminGroupScope.php index d476474..10a3907 100644 --- a/app/Scopes/AdminGroupScope.php +++ b/app/Scopes/AdminGroupScope.php @@ -2,8 +2,8 @@ namespace App\Scopes; -use Adldap\Query\Builder; -use Adldap\Laravel\Scopes\ScopeInterface; +// use Adldap\Query\Builder; +// use Adldap\Laravel\Scopes\ScopeInterface; class AdminGroupScope implements ScopeInterface { @@ -16,9 +16,9 @@ class AdminGroupScope implements ScopeInterface */ public function apply(Builder $query) { - // The distinguished name of our LDAP group. - $distname = config('dataapi.admin_group'); + // // The distinguished name of our LDAP group. + // $distname = config('dataapi.admin_group'); - $query->whereMemberOf($distname); + // $query->whereMemberOf($distname); } } \ No newline at end of file diff --git a/app/Virtual/Models/DirectoryEmployee.php b/app/Virtual/Models/DirectoryEmployee.php deleted file mode 100644 index c779ba7..0000000 --- a/app/Virtual/Models/DirectoryEmployee.php +++ /dev/null @@ -1,124 +0,0 @@ -=5.6 <13.0" + }, + "require-dev": { + "ext-sqlite3": "*", + "fakerphp/faker": "^1.18", + "phpunit/phpunit": "^6.0|^8.0|^9.0|^10.0|^11.0|^12.0" + }, + "suggest": { + "awobaz/blade-active": "Blade directives for the Laravel 'Active' package", + "awobaz/eloquent-auto-append": "Automatically append accessors to model serialization", + "awobaz/eloquent-mutators": "Reusable mutators (getters/setters) for Laravel 5's Eloquent", + "awobaz/syntactic": "Syntactic sugar for named and indexed parameters call." + }, + "type": "library", + "autoload": { + "psr-4": { + "Awobaz\\Compoships\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Claudin J. Daniel", + "email": "cdaniel@awobaz.com" + } + ], + "description": "Laravel relationships with support for composite/multiple keys", + "keywords": [ + "laravel", + "laravel composite keys", + "laravel relationships" + ], + "support": { + "issues": "https://github.com/topclaudy/compoships/issues", + "source": "https://github.com/topclaudy/compoships/tree/2.5.4" + }, + "funding": [ + { + "url": "https://paypal.me/awobaz", + "type": "custom" + } + ], + "time": "2025-12-23T18:33:46+00:00" + }, { "name": "brick/math", - "version": "0.12.3", + "version": "0.14.1", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" + "reference": "f05858549e5f9d7bb45875a75583240a38a281d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", - "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", + "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0", + "reference": "f05858549e5f9d7bb45875a75583240a38a281d0", "shasum": "" }, "require": { - "php": "^8.1" + "php": "^8.2" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^10.1", - "vimeo/psalm": "6.8.8" + "phpstan/phpstan": "2.1.22", + "phpunit/phpunit": "^11.5" }, "type": "library", "autoload": { @@ -56,7 +118,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.12.3" + "source": "https://github.com/brick/math/tree/0.14.1" }, "funding": [ { @@ -64,7 +126,7 @@ "type": "github" } ], - "time": "2025-02-28T13:11:00+00:00" + "time": "2025-11-24T14:40:29+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -136,51 +198,53 @@ "time": "2024-02-09T16:56:22+00:00" }, { - "name": "darkaonline/l5-swagger", - "version": "8.6.5", + "name": "dedoc/scramble", + "version": "v0.13.10", "source": { "type": "git", - "url": "https://github.com/DarkaOnLine/L5-Swagger.git", - "reference": "4cf2b3faae9e9cffd05e4eb6e066741bf56f0a85" + "url": "https://github.com/dedoc/scramble.git", + "reference": "fd73178629c0a5ddc59eeac4fd605d4820b60f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DarkaOnLine/L5-Swagger/zipball/4cf2b3faae9e9cffd05e4eb6e066741bf56f0a85", - "reference": "4cf2b3faae9e9cffd05e4eb6e066741bf56f0a85", + "url": "https://api.github.com/repos/dedoc/scramble/zipball/fd73178629c0a5ddc59eeac4fd605d4820b60f11", + "reference": "fd73178629c0a5ddc59eeac4fd605d4820b60f11", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0 || ^2.0", - "ext-json": "*", - "laravel/framework": "^11.0 || ^10.0 || ^9.0 || >=8.40.0 || ^7.0", - "php": "^7.2 || ^8.0", - "swagger-api/swagger-ui": "^3.0 || >=4.1.3", - "symfony/yaml": "^5.0 || ^6.0 || ^7.0", - "zircote/swagger-php": "^3.2.0 || ^4.0.0" + "illuminate/contracts": "^10.0|^11.0|^12.0", + "myclabs/deep-copy": "^1.12", + "nikic/php-parser": "^5.0", + "php": "^8.1", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "spatie/laravel-package-tools": "^1.9.2" }, "require-dev": { - "mockery/mockery": "1.*", - "orchestra/testbench": "^9.0 || ^8.0 || 7.* || ^6.15 || 5.*", - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^11.0 || ^10.0 || ^9.5" + "larastan/larastan": "^3.3", + "laravel/pint": "^v1.1.0", + "nunomaduro/collision": "^7.0|^8.0", + "orchestra/testbench": "^8.0|^9.0|^10.0", + "pestphp/pest": "^2.34|^3.7", + "pestphp/pest-plugin-laravel": "^2.3|^3.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5|^11.5.3", + "spatie/laravel-permission": "^6.10", + "spatie/pest-plugin-snapshots": "^2.1" }, "type": "library", "extra": { "laravel": { - "aliases": { - "L5Swagger": "L5Swagger\\L5SwaggerFacade" - }, "providers": [ - "L5Swagger\\L5SwaggerServiceProvider" + "Dedoc\\Scramble\\ScrambleServiceProvider" ] } }, "autoload": { - "files": [ - "src/helpers.php" - ], "psr-4": { - "L5Swagger\\": "src" + "Dedoc\\Scramble\\": "src", + "Dedoc\\Scramble\\Database\\Factories\\": "database/factories" } }, "notification-url": "https://packagist.org/downloads/", @@ -189,31 +253,29 @@ ], "authors": [ { - "name": "Darius Matulionis", - "email": "darius@matulionis.lt" + "name": "Roman Lytvynenko", + "email": "litvinenko95@gmail.com", + "role": "Developer" } ], - "description": "OpenApi or Swagger integration to Laravel", + "description": "Automatic generation of API documentation for Laravel applications.", + "homepage": "https://github.com/dedoc/scramble", "keywords": [ - "api", "documentation", "laravel", - "openapi", - "specification", - "swagger", - "ui" + "openapi" ], "support": { - "issues": "https://github.com/DarkaOnLine/L5-Swagger/issues", - "source": "https://github.com/DarkaOnLine/L5-Swagger/tree/8.6.5" + "issues": "https://github.com/dedoc/scramble/issues", + "source": "https://github.com/dedoc/scramble/tree/v0.13.10" }, "funding": [ { - "url": "https://github.com/DarkaOnLine", + "url": "https://github.com/romalytvynenko", "type": "github" } ], - "time": "2025-02-06T14:54:32+00:00" + "time": "2025-12-29T08:30:07+00:00" }, { "name": "dflydev/dot-access-data", @@ -290,254 +352,34 @@ }, "time": "2024-07-08T12:26:09+00:00" }, - { - "name": "directorytree/ldaprecord", - "version": "v3.8.2", - "source": { - "type": "git", - "url": "https://github.com/DirectoryTree/LdapRecord.git", - "reference": "cff35dc485cdfbc68e53948e4842e37e68770dde" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/cff35dc485cdfbc68e53948e4842e37e68770dde", - "reference": "cff35dc485cdfbc68e53948e4842e37e68770dde", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "ext-json": "*", - "ext-ldap": "*", - "illuminate/collections": "^8.0|^9.0|^10.0|^11.0|^12.0", - "illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0", - "nesbot/carbon": "*", - "php": ">=8.1", - "psr/log": "*", - "psr/simple-cache": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "fakerphp/faker": "^1.21", - "laravel/pint": "^1.6", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^9.0", - "spatie/ray": "^1.24" - }, - "type": "library", - "autoload": { - "psr-4": { - "LdapRecord\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Steve Bauman", - "email": "steven_bauman@outlook.com", - "role": "Developer" - } - ], - "description": "A fully-featured LDAP ORM.", - "homepage": "https://www.ldaprecord.com", - "keywords": [ - "active directory", - "ad", - "adLDAP", - "adldap2", - "directory", - "ldap", - "ldaprecord", - "orm", - "windows" - ], - "support": { - "docs": "https://ldaprecord.com", - "email": "steven_bauman@outlook.com", - "issues": "https://github.com/DirectoryTree/LdapRecord/issues", - "source": "https://github.com/DirectoryTree/LdapRecord" - }, - "funding": [ - { - "url": "https://github.com/stevebauman", - "type": "github" - } - ], - "time": "2025-05-20T20:49:13+00:00" - }, - { - "name": "directorytree/ldaprecord-laravel", - "version": "v3.4.1", - "source": { - "type": "git", - "url": "https://github.com/DirectoryTree/LdapRecord-Laravel.git", - "reference": "15f56e01319852d41023633d3688ac4aa139aa6e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/DirectoryTree/LdapRecord-Laravel/zipball/15f56e01319852d41023633d3688ac4aa139aa6e", - "reference": "15f56e01319852d41023633d3688ac4aa139aa6e", - "shasum": "" - }, - "require": { - "directorytree/ldaprecord": "^v3.3", - "ext-json": "*", - "ext-ldap": "*", - "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0", - "php": ">=8.1", - "ramsey/uuid": "*" - }, - "require-dev": { - "laravel/pint": "^1.9", - "laravel/sanctum": "*", - "mockery/mockery": "^1.0", - "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0", - "phpunit/phpunit": "^8.0|^9.0|^10.0|^11.0", - "spatie/ray": "^1.28" - }, - "type": "project", - "extra": { - "laravel": { - "providers": [ - "LdapRecord\\Laravel\\LdapServiceProvider", - "LdapRecord\\Laravel\\LdapAuthServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "LdapRecord\\Laravel\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "LDAP Authentication & Management for Laravel.", - "keywords": [ - "adldap2", - "laravel", - "ldap", - "ldaprecord" - ], - "support": { - "issues": "https://github.com/DirectoryTree/LdapRecord-Laravel/issues", - "source": "https://github.com/DirectoryTree/LdapRecord-Laravel/tree/v3.4.1" - }, - "funding": [ - { - "url": "https://github.com/stevebauman", - "type": "github" - } - ], - "time": "2025-03-21T19:16:44+00:00" - }, - { - "name": "doctrine/annotations", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", - "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^2 || ^3", - "ext-tokenizer": "*", - "php": "^7.2 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.10.28", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^5.4 || ^6.4 || ^7", - "vimeo/psalm": "^4.30 || ^5.14" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/2.0.2" - }, - "time": "2024-09-05T10:17:24+00:00" - }, { "name": "doctrine/inflector", - "version": "2.0.10", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25 || ^5.4" + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + "Doctrine\\Inflector\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -582,7 +424,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.10" + "source": "https://github.com/doctrine/inflector/tree/2.1.0" }, "funding": [ { @@ -598,7 +440,7 @@ "type": "tidelift" } ], - "time": "2024-02-18T20:23:39+00:00" + "time": "2025-08-10T19:31:58+00:00" }, { "name": "doctrine/lexer", @@ -679,29 +521,28 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.4.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "8c784d071debd117328803d86b2097615b457500" + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", - "reference": "8c784d071debd117328803d86b2097615b457500", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "webmozart/assert": "^1.0" + "php": "^8.2|^8.3|^8.4|^8.5" }, "replace": { "mtdowling/cron-expression": "^1.0" }, "require-dev": { - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.0", - "phpunit/phpunit": "^7.0|^8.0|^9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^9.0" }, "type": "library", "extra": { @@ -732,7 +573,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.6.0" }, "funding": [ { @@ -740,7 +581,7 @@ "type": "github" } ], - "time": "2024-10-09T13:47:03+00:00" + "time": "2025-10-31T18:51:33+00:00" }, { "name": "egulias/email-validator", @@ -809,33 +650,96 @@ ], "time": "2025-03-06T22:45:56+00:00" }, + { + "name": "firebase/php-jwt", + "version": "v7.0.2", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "5645b43af647b6947daac1d0f659dd1fbe8d3b65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/5645b43af647b6947daac1d0f659dd1fbe8d3b65", + "reference": "5645b43af647b6947daac1d0f659dd1fbe8d3b65", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v7.0.2" + }, + "time": "2025-12-16T22:17:28+00:00" + }, { "name": "fruitcake/php-cors", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/fruitcake/php-cors.git", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", "shasum": "" }, "require": { - "php": "^7.4|^8.0", - "symfony/http-foundation": "^4.4|^5.4|^6|^7" + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" }, "require-dev": { - "phpstan/phpstan": "^1.4", + "phpstan/phpstan": "^2", "phpunit/phpunit": "^9", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -866,7 +770,7 @@ ], "support": { "issues": "https://github.com/fruitcake/php-cors/issues", - "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0" }, "funding": [ { @@ -878,28 +782,28 @@ "type": "github" } ], - "time": "2023-10-12T05:21:21+00:00" + "time": "2025-12-03T09:33:47+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.1.3", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -928,7 +832,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -940,26 +844,26 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.9.3", + "version": "7.10.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -1050,7 +954,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" }, "funding": [ { @@ -1066,20 +970,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:37:11+00:00" + "time": "2025-08-23T22:36:01+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { @@ -1087,7 +991,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { @@ -1133,7 +1037,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.2.0" + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { @@ -1149,20 +1053,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:27:01+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + "reference": "21dc724a0583619cd1652f673303492272778051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -1178,7 +1082,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1249,7 +1153,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.1" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -1265,20 +1169,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T12:30:47+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.4", + "version": "v1.0.5", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1", "shasum": "" }, "require": { @@ -1287,7 +1191,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.44 || ^9.6.25", "uri-template/tests": "1.0.0" }, "type": "library", @@ -1335,7 +1239,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.5" }, "funding": [ { @@ -1351,24 +1255,24 @@ "type": "tidelift" } ], - "time": "2025-02-03T10:55:03+00:00" + "time": "2025-08-22T14:27:06+00:00" }, { "name": "laravel/framework", - "version": "v11.45.1", + "version": "v12.48.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "b09ba32795b8e71df10856a2694706663984a239" + "reference": "0f0974a9769378ccd9c9935c09b9927f3a606830" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/b09ba32795b8e71df10856a2694706663984a239", - "reference": "b09ba32795b8e71df10856a2694706663984a239", + "url": "https://api.github.com/repos/laravel/framework/zipball/0f0974a9769378ccd9c9935c09b9927f3a606830", + "reference": "0f0974a9769378ccd9c9935c09b9927f3a606830", "shasum": "" }, "require": { - "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", + "brick/math": "^0.11|^0.12|^0.13|^0.14", "composer-runtime-api": "^2.2", "doctrine/inflector": "^2.0.5", "dragonmantank/cron-expression": "^3.4", @@ -1383,32 +1287,34 @@ "fruitcake/php-cors": "^1.3", "guzzlehttp/guzzle": "^7.8.2", "guzzlehttp/uri-template": "^1.0", - "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0", + "laravel/prompts": "^0.3.0", "laravel/serializable-closure": "^1.3|^2.0", "league/commonmark": "^2.7", "league/flysystem": "^3.25.1", "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", "monolog/monolog": "^3.0", - "nesbot/carbon": "^2.72.6|^3.8.4", + "nesbot/carbon": "^3.8.4", "nunomaduro/termwind": "^2.0", "php": "^8.2", "psr/container": "^1.1.1|^2.0.1", "psr/log": "^1.0|^2.0|^3.0", "psr/simple-cache": "^1.0|^2.0|^3.0", "ramsey/uuid": "^4.7", - "symfony/console": "^7.0.3", - "symfony/error-handler": "^7.0.3", - "symfony/finder": "^7.0.3", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", "symfony/http-foundation": "^7.2.0", - "symfony/http-kernel": "^7.0.3", - "symfony/mailer": "^7.0.3", - "symfony/mime": "^7.0.3", - "symfony/polyfill-php83": "^1.31", - "symfony/process": "^7.0.3", - "symfony/routing": "^7.0.3", - "symfony/uid": "^7.0.3", - "symfony/var-dumper": "^7.0.3", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php85": "^1.33", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", "tijsverkoyen/css-to-inline-styles": "^2.2.5", "vlucas/phpdotenv": "^5.6.1", "voku/portable-ascii": "^2.0.2" @@ -1440,6 +1346,7 @@ "illuminate/filesystem": "self.version", "illuminate/hashing": "self.version", "illuminate/http": "self.version", + "illuminate/json-schema": "self.version", "illuminate/log": "self.version", "illuminate/macroable": "self.version", "illuminate/mail": "self.version", @@ -1449,6 +1356,7 @@ "illuminate/process": "self.version", "illuminate/queue": "self.version", "illuminate/redis": "self.version", + "illuminate/reflection": "self.version", "illuminate/routing": "self.version", "illuminate/session": "self.version", "illuminate/support": "self.version", @@ -1472,17 +1380,18 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^9.13.2", - "pda/pheanstalk": "^5.0.6", + "opis/json-schema": "^2.4.1", + "orchestra/testbench-core": "^10.9.0", + "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.5.35|^11.3.6|^12.0.1", - "predis/predis": "^2.3", - "resend/resend-php": "^0.10.0", - "symfony/cache": "^7.0.3", - "symfony/http-client": "^7.0.3", - "symfony/psr-http-message-bridge": "^7.0.3", - "symfony/translation": "^7.0.3" + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3|^3.0", + "resend/resend-php": "^0.10.0|^1.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" }, "suggest": { "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", @@ -1497,7 +1406,7 @@ "ext-pdo": "Required to use all database features.", "ext-posix": "Required to use all features of the queue worker.", "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", - "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "fakerphp/faker": "Required to generate fake data using the fake() helper (^1.23).", "filp/whoops": "Required for friendly error pages in development (^2.14.3).", "laravel/tinker": "Required to use the tinker console command (^2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", @@ -1508,22 +1417,22 @@ "mockery/mockery": "Required to use mocking (^1.6).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", - "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.3.6|^12.0.1).", - "predis/predis": "Required to use the predis connector (^2.3).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3|^3.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", - "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", - "symfony/cache": "Required to PSR-6 cache bridge (^7.0).", - "symfony/filesystem": "Required to enable support for relative symbolic links (^7.0).", - "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.0).", - "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.0).", - "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.0).", - "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.0)." + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0|^1.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "11.x-dev" + "dev-master": "12.x-dev" } }, "autoload": { @@ -1534,6 +1443,7 @@ "src/Illuminate/Filesystem/functions.php", "src/Illuminate/Foundation/helpers.php", "src/Illuminate/Log/functions.php", + "src/Illuminate/Reflection/helpers.php", "src/Illuminate/Support/functions.php", "src/Illuminate/Support/helpers.php" ], @@ -1542,7 +1452,8 @@ "Illuminate\\Support\\": [ "src/Illuminate/Macroable/", "src/Illuminate/Collections/", - "src/Illuminate/Conditionable/" + "src/Illuminate/Conditionable/", + "src/Illuminate/Reflection/" ] } }, @@ -1566,20 +1477,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-06-03T14:01:40+00:00" + "time": "2026-01-20T16:12:36+00:00" }, { "name": "laravel/helpers", - "version": "v1.7.2", + "version": "v1.8.2", "source": { "type": "git", "url": "https://github.com/laravel/helpers.git", - "reference": "672d79d5b5f65dc821e57783fa11f22c4d762d70" + "reference": "98499eea4c1cca76fb0fb37ed365a468773daf0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/helpers/zipball/672d79d5b5f65dc821e57783fa11f22c4d762d70", - "reference": "672d79d5b5f65dc821e57783fa11f22c4d762d70", + "url": "https://api.github.com/repos/laravel/helpers/zipball/98499eea4c1cca76fb0fb37ed365a468773daf0a", + "reference": "98499eea4c1cca76fb0fb37ed365a468773daf0a", "shasum": "" }, "require": { @@ -1588,7 +1499,7 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^7.0|^8.0|^9.0|^10.0" + "phpunit/phpunit": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0" }, "type": "library", "extra": { @@ -1621,9 +1532,9 @@ "laravel" ], "support": { - "source": "https://github.com/laravel/helpers/tree/v1.7.2" + "source": "https://github.com/laravel/helpers/tree/v1.8.2" }, - "time": "2025-01-24T15:41:25+00:00" + "time": "2025-11-25T14:46:28+00:00" }, { "name": "laravel/legacy-factories", @@ -1683,16 +1594,16 @@ }, { "name": "laravel/prompts", - "version": "v0.3.5", + "version": "v0.3.10", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1" + "reference": "360ba095ef9f51017473505191fbd4ab73e1cab3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1", - "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1", + "url": "https://api.github.com/repos/laravel/prompts/zipball/360ba095ef9f51017473505191fbd4ab73e1cab3", + "reference": "360ba095ef9f51017473505191fbd4ab73e1cab3", "shasum": "" }, "require": { @@ -1708,9 +1619,9 @@ "require-dev": { "illuminate/collections": "^10.0|^11.0|^12.0", "mockery/mockery": "^1.5", - "pestphp/pest": "^2.3|^3.4", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-mockery": "^1.1" + "pestphp/pest": "^2.3|^3.4|^4.0", + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" }, "suggest": { "ext-pcntl": "Required for the spinner to be animated." @@ -1736,22 +1647,22 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.5" + "source": "https://github.com/laravel/prompts/tree/v0.3.10" }, - "time": "2025-02-11T13:34:40+00:00" + "time": "2026-01-13T20:29:29+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.4", + "version": "v2.0.8", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", - "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b", + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b", "shasum": "" }, "require": { @@ -1760,7 +1671,7 @@ "require-dev": { "illuminate/support": "^10.0|^11.0|^12.0", "nesbot/carbon": "^2.67|^3.0", - "pestphp/pest": "^2.36|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/phpstan": "^2.0", "symfony/var-dumper": "^6.2.0|^7.0.0" }, @@ -1799,49 +1710,56 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2025-03-19T13:51:03+00:00" + "time": "2026-01-08T16:22:46+00:00" }, { - "name": "laravel/tinker", - "version": "v2.10.1", + "name": "laravel/socialite", + "version": "v5.24.2", "source": { "type": "git", - "url": "https://github.com/laravel/tinker.git", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + "url": "https://github.com/laravel/socialite.git", + "reference": "5cea2eebf11ca4bc6c2f20495c82a70a9b3d1613" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "url": "https://api.github.com/repos/laravel/socialite/zipball/5cea2eebf11ca4bc6c2f20495c82a70a9b3d1613", + "reference": "5cea2eebf11ca4bc6c2f20495c82a70a9b3d1613", "shasum": "" }, "require": { - "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "ext-json": "*", + "firebase/php-jwt": "^6.4|^7.0", + "guzzlehttp/guzzle": "^6.0|^7.0", "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", - "php": "^7.2.5|^8.0", - "psy/psysh": "^0.11.1|^0.12.0", - "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + "league/oauth1-client": "^1.11", + "php": "^7.2|^8.0", + "phpseclib/phpseclib": "^3.0" }, "require-dev": { - "mockery/mockery": "~1.3.3|^1.4.2", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" - }, - "suggest": { - "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.18|^5.20|^6.47|^7.55|^8.36|^9.15|^10.8", + "phpstan/phpstan": "^1.12.23", + "phpunit/phpunit": "^8.0|^9.3|^10.4|^11.5|^12.0" }, "type": "library", "extra": { "laravel": { + "aliases": { + "Socialite": "Laravel\\Socialite\\Facades\\Socialite" + }, "providers": [ - "Laravel\\Tinker\\TinkerServiceProvider" + "Laravel\\Socialite\\SocialiteServiceProvider" ] + }, + "branch-alias": { + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "Laravel\\Tinker\\": "src/" + "Laravel\\Socialite\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1854,7 +1772,72 @@ "email": "taylor@laravel.com" } ], - "description": "Powerful REPL for the Laravel framework.", + "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.", + "homepage": "https://laravel.com", + "keywords": [ + "laravel", + "oauth" + ], + "support": { + "issues": "https://github.com/laravel/socialite/issues", + "source": "https://github.com/laravel/socialite" + }, + "time": "2026-01-10T16:07:28+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.11.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468", + "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "php": "^7.2.5|^8.0", + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0|^8.0" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", "keywords": [ "REPL", "Tinker", @@ -1863,9 +1846,9 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.10.1" + "source": "https://github.com/laravel/tinker/tree/v2.11.0" }, - "time": "2025-01-27T14:24:01+00:00" + "time": "2025-12-19T19:16:45+00:00" }, { "name": "laravel/ui", @@ -1932,34 +1915,34 @@ }, { "name": "lcobucci/clock", - "version": "3.3.1", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/lcobucci/clock.git", - "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b" + "reference": "a3139d9e97d47826f27e6a17bb63f13621f86058" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/clock/zipball/db3713a61addfffd615b79bf0bc22f0ccc61b86b", - "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/a3139d9e97d47826f27e6a17bb63f13621f86058", + "reference": "a3139d9e97d47826f27e6a17bb63f13621f86058", "shasum": "" }, "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "php": "~8.3.0 || ~8.4.0 || ~8.5.0", "psr/clock": "^1.0" }, "provide": { "psr/clock-implementation": "1.0" }, "require-dev": { - "infection/infection": "^0.29", - "lcobucci/coding-standard": "^11.1.0", + "infection/infection": "^0.31", + "lcobucci/coding-standard": "^11.2.0", "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.10.25", - "phpstan/phpstan-deprecation-rules": "^1.1.3", - "phpstan/phpstan-phpunit": "^1.3.13", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^11.3.6" + "phpstan/phpstan": "^2.0.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0.0", + "phpstan/phpstan-strict-rules": "^2.0.0", + "phpunit/phpunit": "^12.0.0" }, "type": "library", "autoload": { @@ -1980,7 +1963,7 @@ "description": "Yet another clock abstraction", "support": { "issues": "https://github.com/lcobucci/clock/issues", - "source": "https://github.com/lcobucci/clock/tree/3.3.1" + "source": "https://github.com/lcobucci/clock/tree/3.5.0" }, "funding": [ { @@ -1992,7 +1975,7 @@ "type": "patreon" } ], - "time": "2024-09-24T20:45:14+00:00" + "time": "2025-10-27T09:03:17+00:00" }, { "name": "lcobucci/jwt", @@ -2070,16 +2053,16 @@ }, { "name": "league/commonmark", - "version": "2.7.0", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405" + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", - "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", "shasum": "" }, "require": { @@ -2108,7 +2091,7 @@ "symfony/process": "^5.4 | ^6.0 | ^7.0", "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", "unleashedtech/php-coding-standard": "^3.1.1", - "vimeo/psalm": "^4.24.0 || ^5.0.0" + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, "suggest": { "symfony/yaml": "v2.3+ required if using the Front Matter extension" @@ -2116,7 +2099,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.8-dev" + "dev-main": "2.9-dev" } }, "autoload": { @@ -2173,7 +2156,7 @@ "type": "tidelift" } ], - "time": "2025-05-05T12:20:28+00:00" + "time": "2025-11-26T21:48:24+00:00" }, { "name": "league/config", @@ -2259,16 +2242,16 @@ }, { "name": "league/flysystem", - "version": "3.29.1", + "version": "3.30.2", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319" + "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319", - "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277", + "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277", "shasum": "" }, "require": { @@ -2292,13 +2275,13 @@ "composer/semver": "^3.0", "ext-fileinfo": "*", "ext-ftp": "*", - "ext-mongodb": "^1.3", + "ext-mongodb": "^1.3|^2", "ext-zip": "*", "friendsofphp/php-cs-fixer": "^3.5", "google/cloud-storage": "^1.23", "guzzlehttp/psr7": "^2.6", "microsoft/azure-storage-blob": "^1.1", - "mongodb/mongodb": "^1.2", + "mongodb/mongodb": "^1.2|^2", "phpseclib/phpseclib": "^3.0.36", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.5.11|^10.0", @@ -2336,22 +2319,22 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.29.1" + "source": "https://github.com/thephpleague/flysystem/tree/3.30.2" }, - "time": "2024-10-08T08:58:34+00:00" + "time": "2025-11-10T17:13:11+00:00" }, { "name": "league/flysystem-local", - "version": "3.29.0", + "version": "3.30.2", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" + "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", - "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ab4f9d0d672f601b102936aa728801dd1a11968d", + "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d", "shasum": "" }, "require": { @@ -2385,9 +2368,9 @@ "local" ], "support": { - "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.2" }, - "time": "2024-08-09T21:24:39+00:00" + "time": "2025-11-10T11:23:37+00:00" }, { "name": "league/fractal", @@ -2515,35 +2498,116 @@ ], "time": "2024-09-21T08:32:55+00:00" }, + { + "name": "league/oauth1-client", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth1-client.git", + "reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/f9c94b088837eb1aae1ad7c4f23eb65cc6993055", + "reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=7.1||>=8.0" + }, + "require-dev": { + "ext-simplexml": "*", + "friendsofphp/php-cs-fixer": "^2.17", + "mockery/mockery": "^1.3.3", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5||9.5" + }, + "suggest": { + "ext-simplexml": "For decoding XML-based responses." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev", + "dev-develop": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth1\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Corlett", + "email": "bencorlett@me.com", + "homepage": "http://www.webcomm.com.au", + "role": "Developer" + } + ], + "description": "OAuth 1.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "bitbucket", + "identity", + "idp", + "oauth", + "oauth1", + "single sign on", + "trello", + "tumblr", + "twitter" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth1-client/issues", + "source": "https://github.com/thephpleague/oauth1-client/tree/v1.11.0" + }, + "time": "2024-12-10T19:59:05+00:00" + }, { "name": "league/uri", - "version": "7.5.1", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "league/uri-interfaces": "^7.8", + "php": "^8.1", + "psr/http-factory": "^1" }, "conflict": { "league/uri-schemes": "^1.0" }, "suggest": { "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -2571,6 +2635,7 @@ "description": "URI manipulation library", "homepage": "https://uri.thephpleague.com", "keywords": [ + "URN", "data-uri", "file-uri", "ftp", @@ -2583,9 +2648,11 @@ "psr-7", "query-string", "querystring", + "rfc2141", "rfc3986", "rfc3987", "rfc6570", + "rfc8141", "uri", "uri-template", "url", @@ -2595,7 +2662,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "source": "https://github.com/thephpleague/uri/tree/7.8.0" }, "funding": [ { @@ -2603,26 +2670,25 @@ "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2026-01-14T17:24:56+00:00" }, { "name": "league/uri-interfaces", - "version": "7.5.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", "shasum": "" }, "require": { "ext-filter": "*", "php": "^8.1", - "psr/http-factory": "^1", "psr/http-message": "^1.1 || ^2.0" }, "suggest": { @@ -2630,6 +2696,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -2654,7 +2721,7 @@ "homepage": "https://nyamsprod.com" } ], - "description": "Common interfaces and classes for URI representation and interaction", + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", "homepage": "https://uri.thephpleague.com", "keywords": [ "data-uri", @@ -2679,7 +2746,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" }, "funding": [ { @@ -2687,20 +2754,20 @@ "type": "github" } ], - "time": "2024-12-08T08:18:47+00:00" + "time": "2026-01-15T06:54:53+00:00" }, { "name": "monolog/monolog", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { @@ -2718,7 +2785,7 @@ "graylog2/gelf-php": "^1.4.2 || ^2.0", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", + "mongodb/mongodb": "^1.8 || ^2.0", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.8", "phpstan/phpstan": "^2", @@ -2778,7 +2845,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { @@ -2790,20 +2857,80 @@ "type": "tidelift" } ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-01-02T08:56:05+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" }, { "name": "nesbot/carbon", - "version": "3.9.1", + "version": "3.11.0", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "ced71f79398ece168e24f7f7710462f462310d4d" + "reference": "bdb375400dcd162624531666db4799b36b64e4a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ced71f79398ece168e24f7f7710462f462310d4d", - "reference": "ced71f79398ece168e24f7f7710462f462310d4d", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1", + "reference": "bdb375400dcd162624531666db4799b36b64e4a1", "shasum": "" }, "require": { @@ -2811,9 +2938,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -2821,14 +2948,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.57.2", + "friendsofphp/php-cs-fixer": "^v3.87.1", "kylekatarnls/multi-tester": "^2.5.3", - "ondrejmirtes/better-reflection": "^6.25.0.4", "phpmd/phpmd": "^2.15.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.11.2", - "phpunit/phpunit": "^10.5.20", - "squizlabs/php_codesniffer": "^3.9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4" }, "bin": [ "bin/carbon" @@ -2896,29 +3022,29 @@ "type": "tidelift" } ], - "time": "2025-05-01T19:51:51+00:00" + "time": "2025-12-02T21:04:28+00:00" }, { "name": "nette/schema", - "version": "v1.3.2", + "version": "v1.3.3", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", - "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", + "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", "shasum": "" }, "require": { "nette/utils": "^4.0", - "php": "8.1 - 8.4" + "php": "8.1 - 8.5" }, "require-dev": { "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^1.0", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -2928,6 +3054,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -2956,35 +3085,35 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.2" + "source": "https://github.com/nette/schema/tree/v1.3.3" }, - "time": "2024-10-06T23:10:23+00:00" + "time": "2025-10-30T22:57:59+00:00" }, { "name": "nette/utils", - "version": "v4.0.7", + "version": "v4.1.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72", + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72", "shasum": "" }, "require": { - "php": "8.0 - 8.4" + "php": "8.2 - 8.5" }, "conflict": { "nette/finder": "<3", "nette/schema": "<1.2.2" }, "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", + "jetbrains/phpstorm-attributes": "^1.2", "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -2998,10 +3127,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -3042,22 +3174,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.7" + "source": "https://github.com/nette/utils/tree/v4.1.1" }, - "time": "2025-06-03T04:55:08+00:00" + "time": "2025-12-22T12:14:32+00:00" }, { "name": "nikic/php-parser", - "version": "v5.5.0", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -3076,7 +3208,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -3100,37 +3232,37 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-05-31T08:24:38+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "nunomaduro/termwind", - "version": "v2.3.1", + "version": "v2.3.3", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "dfa08f390e509967a15c22493dc0bac5733d9123" + "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123", - "reference": "dfa08f390e509967a15c22493dc0bac5733d9123", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017", + "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.2.6" + "symfony/console": "^7.3.6" }, "require-dev": { - "illuminate/console": "^11.44.7", - "laravel/pint": "^1.22.0", + "illuminate/console": "^11.46.1", + "laravel/pint": "^1.25.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.2", - "phpstan/phpstan": "^1.12.25", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3", + "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.2.6", + "symfony/var-dumper": "^7.3.5", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -3173,7 +3305,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1" + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.3" }, "funding": [ { @@ -3189,20 +3321,139 @@ "type": "github" } ], - "time": "2025-05-08T08:14:37+00:00" + "time": "2025-11-20T02:34:59+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.1.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2025-09-24T15:06:41+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -3210,7 +3461,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -3252,7 +3503,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -3264,34 +3515,44 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { - "name": "psr/cache", - "version": "3.0.0", + "name": "phpseclib/phpseclib", + "version": "3.0.48", "source": { "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "64065a5679c50acb886e82c07aa139b0f757bb89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/64065a5679c50acb886e82c07aa139b0f757bb89", + "reference": "64065a5679c50acb886e82c07aa139b0f757bb89", "shasum": "" }, "require": { - "php": ">=8.0.0" + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." }, + "type": "library", "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], "psr-4": { - "Psr\\Cache\\": "src/" + "phpseclib3\\": "phpseclib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3300,22 +3561,120 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" } ], - "description": "Common interface for caching libraries", + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", "keywords": [ - "cache", - "psr", - "psr-6" + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" ], "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.48" }, - "time": "2021-02-03T23:26:27+00:00" - }, - { + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2025-12-15T11:51:42+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/16dbf9937da8d4528ceb2145c9c7c0bd29e26374", + "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.1" + }, + "time": "2026-01-12T11:33:04+00:00" + }, + { "name": "psr/clock", "version": "1.0.0", "source": { @@ -3729,16 +4088,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.8", + "version": "v0.12.18", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625" + "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625", - "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/ddff0ac01beddc251786fe70367cd8bbdb258196", + "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196", "shasum": "" }, "require": { @@ -3746,18 +4105,19 @@ "ext-tokenizer": "*", "nikic/php-parser": "^5.0 || ^4.0", "php": "^8.0 || ^7.4", - "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", - "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" }, "conflict": { "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.2" + "bamarni/composer-bin-plugin": "^1.2", + "composer/class-map-generator": "^1.6" }, "suggest": { + "composer/class-map-generator": "Improved tab completion performance with better class discovery.", "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", - "ext-pdo-sqlite": "The doc command requires SQLite to work.", "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." }, "bin": [ @@ -3788,12 +4148,11 @@ "authors": [ { "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "email": "justin@justinhileman.info" } ], "description": "An interactive shell for modern PHP.", - "homepage": "http://psysh.org", + "homepage": "https://psysh.org", "keywords": [ "REPL", "console", @@ -3802,9 +4161,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.8" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.18" }, - "time": "2025-03-16T03:05:19+00:00" + "time": "2025-12-17T14:35:46+00:00" }, { "name": "ralouphie/getallheaders", @@ -3928,21 +4287,20 @@ }, { "name": "ramsey/uuid", - "version": "4.8.1", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28" + "reference": "8429c78ca35a09f27565311b98101e2826affde0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", - "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", - "ext-json": "*", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -4001,83 +4359,208 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.8.1" + "source": "https://github.com/ramsey/uuid/tree/4.9.2" }, - "time": "2025-06-01T06:28:46+00:00" + "time": "2025-12-14T04:43:48+00:00" }, { - "name": "swagger-api/swagger-ui", - "version": "v5.22.0", + "name": "socialiteproviders/manager", + "version": "v4.8.1", "source": { "type": "git", - "url": "https://github.com/swagger-api/swagger-ui.git", - "reference": "4b37bf2a25a8d82fb0092b25d8108d1bb4171181" + "url": "https://github.com/SocialiteProviders/Manager.git", + "reference": "8180ec14bef230ec2351cff993d5d2d7ca470ef4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/4b37bf2a25a8d82fb0092b25d8108d1bb4171181", - "reference": "4b37bf2a25a8d82fb0092b25d8108d1bb4171181", + "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/8180ec14bef230ec2351cff993d5d2d7ca470ef4", + "reference": "8180ec14bef230ec2351cff993d5d2d7ca470ef4", "shasum": "" }, + "require": { + "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", + "laravel/socialite": "^5.5", + "php": "^8.1" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^9.0" + }, "type": "library", + "extra": { + "laravel": { + "providers": [ + "SocialiteProviders\\Manager\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "SocialiteProviders\\Manager\\": "src/" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "authors": [ { - "name": "Anna Bodnia", - "email": "anna.bodnia@gmail.com" + "name": "Andy Wendt", + "email": "andy@awendt.com" }, { - "name": "Buu Nguyen", - "email": "buunguyen@gmail.com" + "name": "Anton Komarev", + "email": "a.komarev@cybercog.su" }, { - "name": "Josh Ponelat", - "email": "jponelat@gmail.com" + "name": "Miguel Piedrafita", + "email": "soy@miguelpiedrafita.com" }, { - "name": "Kyle Shockey", - "email": "kyleshockey1@gmail.com" - }, + "name": "atymic", + "email": "atymicq@gmail.com", + "homepage": "https://atymic.dev" + } + ], + "description": "Easily add new or override built-in providers in Laravel Socialite.", + "homepage": "https://socialiteproviders.com", + "keywords": [ + "laravel", + "manager", + "oauth", + "providers", + "socialite" + ], + "support": { + "issues": "https://github.com/socialiteproviders/manager/issues", + "source": "https://github.com/socialiteproviders/manager" + }, + "time": "2025-02-24T19:33:30+00:00" + }, + { + "name": "socialiteproviders/microsoft-azure", + "version": "5.2.0", + "source": { + "type": "git", + "url": "https://github.com/SocialiteProviders/Microsoft-Azure.git", + "reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SocialiteProviders/Microsoft-Azure/zipball/453d62c9d7e3b3b76e94c913fb46e68a33347b16", + "reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^8.0", + "socialiteproviders/manager": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "SocialiteProviders\\Azure\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "Robert Barnwell", - "email": "robert@robertismy.name" - }, + "name": "Chris Hemmings", + "email": "chris@hemmin.gs" + } + ], + "description": "Microsoft Azure OAuth2 Provider for Laravel Socialite", + "keywords": [ + "azure", + "laravel", + "microsoft", + "oauth", + "provider", + "socialite" + ], + "support": { + "docs": "https://socialiteproviders.com/microsoft-azure", + "issues": "https://github.com/socialiteproviders/providers/issues", + "source": "https://github.com/socialiteproviders/providers" + }, + "time": "2024-03-15T03:02:10+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.92.7", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "f09a799850b1ed765103a4f0b4355006360c49a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/f09a799850b1ed765103a4f0b4355006360c49a5", + "reference": "f09a799850b1ed765103a4f0b4355006360c49a5", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.28|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^7.7|^8.0|^9.0|^10.0", + "pestphp/pest": "^1.23|^2.1|^3.1", + "phpunit/php-code-coverage": "^9.0|^10.0|^11.0", + "phpunit/phpunit": "^9.5.24|^10.5|^11.5", + "spatie/pest-plugin-test-time": "^1.1|^2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "Sahar Jafari", - "email": "shr.jafari@gmail.com" + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" } ], - "description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.", - "homepage": "http://swagger.io", + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", "keywords": [ - "api", - "documentation", - "openapi", - "specification", - "swagger", - "ui" + "laravel-package-tools", + "spatie" ], "support": { - "issues": "https://github.com/swagger-api/swagger-ui/issues", - "source": "https://github.com/swagger-api/swagger-ui/tree/v5.22.0" + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.92.7" }, - "time": "2025-05-21T12:44:47+00:00" + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-07-17T15:46:43+00:00" }, { "name": "symfony/clock", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", "shasum": "" }, "require": { @@ -4122,7 +4605,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.3.0" + "source": "https://github.com/symfony/clock/tree/v7.4.0" }, "funding": [ { @@ -4133,25 +4616,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/console", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", - "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", + "url": "https://api.github.com/repos/symfony/console/zipball/732a9ca6cd9dfd940c639062d5edbde2f6727fb6", + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6", "shasum": "" }, "require": { @@ -4159,7 +4646,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" + "symfony/string": "^7.2|^8.0" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -4173,16 +4660,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4216,7 +4703,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.0" + "source": "https://github.com/symfony/console/tree/v7.4.3" }, "funding": [ { @@ -4227,25 +4714,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T10:34:04+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/css-selector", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab862f478513e7ca2fe9ec117a6f01a8da6e1135", + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135", "shasum": "" }, "require": { @@ -4281,7 +4772,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.0" + "source": "https://github.com/symfony/css-selector/tree/v7.4.0" }, "funding": [ { @@ -4292,12 +4783,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-10-30T13:39:42+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4368,32 +4863,33 @@ }, { "name": "symfony/error-handler", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "cf68d225bc43629de4ff54778029aee6dc191b83" + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/cf68d225bc43629de4ff54778029aee6dc191b83", - "reference": "cf68d225bc43629de4ff54778029aee6dc191b83", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/48be2b0653594eea32dcef130cca1c811dcf25c2", + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "conflict": { "symfony/deprecation-contracts": "<2.5", "symfony/http-kernel": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ @@ -4425,7 +4921,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.0" + "source": "https://github.com/symfony/error-handler/tree/v7.4.0" }, "funding": [ { @@ -4436,25 +4932,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-29T07:19:49+00:00" + "time": "2025-11-05T14:29:59+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9dddcddff1ef974ad87b3708e4b442dc38b2261d", + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d", "shasum": "" }, "require": { @@ -4471,13 +4971,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4505,7 +5006,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.0" }, "funding": [ { @@ -4516,12 +5017,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-22T09:11:45+00:00" + "time": "2025-10-28T09:38:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4601,23 +5106,23 @@ }, { "name": "symfony/finder", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" + "reference": "fffe05569336549b20a1be64250b40516d6e8d06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", + "url": "https://api.github.com/repos/symfony/finder/zipball/fffe05569336549b20a1be64250b40516d6e8d06", + "reference": "fffe05569336549b20a1be64250b40516d6e8d06", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4645,7 +5150,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.0" + "source": "https://github.com/symfony/finder/tree/v7.4.3" }, "funding": [ { @@ -4656,32 +5161,35 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-30T19:00:26+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "4236baf01609667d53b20371486228231eb135fd" + "reference": "a70c745d4cea48dbd609f4075e5f5cbce453bd52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4236baf01609667d53b20371486228231eb135fd", - "reference": "4236baf01609667d53b20371486228231eb135fd", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a70c745d4cea48dbd609f4075e5f5cbce453bd52", + "reference": "a70c745d4cea48dbd609f4075e5f5cbce453bd52", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { "doctrine/dbal": "<3.6", @@ -4690,13 +5198,13 @@ "require-dev": { "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/clock": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0" + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4724,7 +5232,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.0" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.3" }, "funding": [ { @@ -4735,34 +5243,38 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-12T14:48:23+00:00" + "time": "2025-12-23T14:23:49+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f" + "reference": "885211d4bed3f857b8c964011923528a55702aa5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ac7b8e163e8c83dce3abcc055a502d4486051a9f", - "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/885211d4bed3f857b8c964011923528a55702aa5", + "reference": "885211d4bed3f857b8c964011923528a55702aa5", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^7.3", - "symfony/http-foundation": "^7.3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -4772,6 +5284,7 @@ "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", "symfony/form": "<6.4", "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", @@ -4789,27 +5302,27 @@ }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^7.1", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^7.1", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "type": "library", @@ -4838,7 +5351,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.0" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.3" }, "funding": [ { @@ -4849,25 +5362,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-29T07:47:32+00:00" + "time": "2025-12-31T08:43:57+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c" + "reference": "e472d35e230108231ccb7f51eb6b2100cac02ee4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/0f375bbbde96ae8c78e4aa3e63aabd486e33364c", - "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c", + "url": "https://api.github.com/repos/symfony/mailer/zipball/e472d35e230108231ccb7f51eb6b2100cac02ee4", + "reference": "e472d35e230108231ccb7f51eb6b2100cac02ee4", "shasum": "" }, "require": { @@ -4875,8 +5392,8 @@ "php": ">=8.2", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -4887,10 +5404,10 @@ "symfony/twig-bridge": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4918,7 +5435,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.0" + "source": "https://github.com/symfony/mailer/tree/v7.4.3" }, "funding": [ { @@ -4929,29 +5446,34 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-04T09:51:09+00:00" + "time": "2025-12-16T08:02:06+00:00" }, { "name": "symfony/mime", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9" + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", + "url": "https://api.github.com/repos/symfony/mime/zipball/bdb02729471be5d047a3ac4a69068748f1a6be7a", + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, @@ -4966,11 +5488,11 @@ "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -5002,7 +5524,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.0" + "source": "https://github.com/symfony/mime/tree/v7.4.0" }, "funding": [ { @@ -5013,16 +5535,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-19T08:51:26+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5081,7 +5607,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -5092,6 +5618,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5101,16 +5631,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -5159,7 +5689,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -5170,16 +5700,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -5242,7 +5776,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -5253,6 +5787,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5262,7 +5800,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -5323,7 +5861,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -5334,6 +5872,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5343,7 +5885,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -5404,7 +5946,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -5415,6 +5957,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5424,7 +5970,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -5484,7 +6030,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -5495,6 +6041,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5504,16 +6054,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -5560,7 +6110,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -5571,36 +6121,34 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { - "name": "symfony/polyfill-uuid", - "version": "v1.32.0", + "name": "symfony/polyfill-php84", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", "shasum": "" }, "require": { "php": ">=7.2" }, - "provide": { - "ext-uuid": "*" - }, - "suggest": { - "ext-uuid": "For best performance" - }, "type": "library", "extra": { "thanks": { @@ -5613,8 +6161,11 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Uuid\\": "" - } + "Symfony\\Polyfill\\Php84\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5622,24 +6173,24 @@ ], "authors": [ { - "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for uuid functions", + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", "polyfill", "portable", - "uuid" + "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" }, "funding": [ { @@ -5650,37 +6201,50 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-24T13:30:11+00:00" }, { - "name": "symfony/process", - "version": "v7.3.0", + "name": "symfony/polyfill-php85", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Process\\": "" + "Symfony\\Polyfill\\Php85\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5689,18 +6253,24 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Executes commands in sub-processes", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" }, "funding": [ { @@ -5711,25 +6281,177 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2025-06-23T16:12:55+00:00" }, { - "name": "symfony/routing", - "version": "v7.3.0", + "name": "symfony/polyfill-uuid", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "8e213820c5fea844ecea29203d2a308019007c15" + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "2f8e1a6cdf590ca63715da4d3a7a3327404a523f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/2f8e1a6cdf590ca63715da4d3a7a3327404a523f", + "reference": "2f8e1a6cdf590ca63715da4d3a7a3327404a523f", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-12-19T10:00:43+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15", - "reference": "8e213820c5fea844ecea29203d2a308019007c15", + "url": "https://api.github.com/repos/symfony/routing/zipball/5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090", + "reference": "5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090", "shasum": "" }, "require": { @@ -5743,11 +6465,11 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5781,7 +6503,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.0" + "source": "https://github.com/symfony/routing/tree/v7.4.3" }, "funding": [ { @@ -5792,25 +6514,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T20:43:28+00:00" + "time": "2025-12-19T10:00:43+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -5864,7 +6590,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -5875,31 +6601,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003", + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -5907,12 +6638,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5951,7 +6681,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.0" + "source": "https://github.com/symfony/string/tree/v7.4.0" }, "funding": [ { @@ -5962,32 +6692,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-20T20:19:01+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/translation", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "4aba29076a29a3aa667e09b791e5f868973a8667" + "reference": "7ef27c65d78886f7599fdd5c93d12c9243ecf44d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/4aba29076a29a3aa667e09b791e5f868973a8667", - "reference": "4aba29076a29a3aa667e09b791e5f868973a8667", + "url": "https://api.github.com/repos/symfony/translation/zipball/7ef27c65d78886f7599fdd5c93d12c9243ecf44d", + "reference": "7ef27c65d78886f7599fdd5c93d12c9243ecf44d", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { "nikic/php-parser": "<5.0", @@ -6006,17 +6740,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6047,7 +6781,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.0" + "source": "https://github.com/symfony/translation/tree/v7.4.3" }, "funding": [ { @@ -6058,25 +6792,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-29T07:19:49+00:00" + "time": "2025-12-29T09:31:36+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { @@ -6125,7 +6863,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -6136,25 +6874,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-27T08:32:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/uid", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3" + "reference": "2498e9f81b7baa206f44de583f2f48350b90142c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/7beeb2b885cd584cd01e126c5777206ae4c3c6a3", - "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3", + "url": "https://api.github.com/repos/symfony/uid/zipball/2498e9f81b7baa206f44de583f2f48350b90142c", + "reference": "2498e9f81b7baa206f44de583f2f48350b90142c", "shasum": "" }, "require": { @@ -6162,7 +6904,7 @@ "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6199,7 +6941,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.0" + "source": "https://github.com/symfony/uid/tree/v7.4.0" }, "funding": [ { @@ -6210,25 +6952,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T14:28:13+00:00" + "time": "2025-09-25T11:02:55+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.0", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e" + "reference": "7e99bebcb3f90d8721890f2963463280848cba92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/548f6760c54197b1084e1e5c71f6d9d523f2f78e", - "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7e99bebcb3f90d8721890f2963463280848cba92", + "reference": "7e99bebcb3f90d8721890f2963463280848cba92", "shasum": "" }, "require": { @@ -6240,11 +6986,10 @@ "symfony/console": "<6.4" }, "require-dev": { - "ext-iconv": "*", - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -6283,7 +7028,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.0" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.3" }, "funding": [ { @@ -6295,75 +7040,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-04-27T18:39:23+00:00" - }, - { - "name": "symfony/yaml", - "version": "v7.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "cea40a48279d58dc3efee8112634cb90141156c2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/cea40a48279d58dc3efee8112634cb90141156c2", - "reference": "cea40a48279d58dc3efee8112634cb90141156c2", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/console": "<6.4" - }, - "require-dev": { - "symfony/console": "^6.4|^7.0" - }, - "bin": [ - "Resources/bin/yaml-lint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Loads and dumps YAML files", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -6371,27 +7048,27 @@ "type": "tidelift" } ], - "time": "2025-04-04T10:10:33+00:00" + "time": "2025-12-18T07:04:31+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^7.4 || ^8.0", - "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^2.0", @@ -6424,9 +7101,9 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0" }, - "time": "2024-12-21T16:25:41+00:00" + "time": "2025-12-02T11:56:42+00:00" }, { "name": "tymon/jwt-auth", @@ -6514,26 +7191,26 @@ }, { "name": "vlucas/phpdotenv", - "version": "v5.6.2", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -6582,7 +7259,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -6594,7 +7271,7 @@ "type": "tidelift" } ], - "time": "2025-04-30T23:37:27+00:00" + "time": "2025-12-27T19:49:13+00:00" }, { "name": "voku/portable-ascii", @@ -6614,228 +7291,89 @@ "php": ">=7.0.0" }, "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" - }, - "suggest": { - "ext-intl": "Use Intl for transliterator_transliterate() support" - }, - "type": "library", - "autoload": { - "psr-4": { - "voku\\": "src/voku/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Lars Moelleken", - "homepage": "https://www.moelleken.org/" - } - ], - "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", - "homepage": "https://github.com/voku/portable-ascii", - "keywords": [ - "ascii", - "clean", - "php" - ], - "support": { - "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.3" - }, - "funding": [ - { - "url": "https://www.paypal.me/moelleken", - "type": "custom" - }, - { - "url": "https://github.com/voku", - "type": "github" - }, - { - "url": "https://opencollective.com/portable-ascii", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", - "type": "tidelift" - } - ], - "time": "2024-11-21T01:49:47+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "time": "2022-06-03T18:03:27+00:00" - }, - { - "name": "zircote/swagger-php", - "version": "4.11.1", - "source": { - "type": "git", - "url": "https://github.com/zircote/swagger-php.git", - "reference": "7df10e8ec47db07c031db317a25bef962b4e5de1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/7df10e8ec47db07c031db317a25bef962b4e5de1", - "reference": "7df10e8ec47db07c031db317a25bef962b4e5de1", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=7.2", - "psr/log": "^1.1 || ^2.0 || ^3.0", - "symfony/deprecation-contracts": "^2 || ^3", - "symfony/finder": ">=2.2", - "symfony/yaml": ">=3.3" - }, - "require-dev": { - "composer/package-versions-deprecated": "^1.11", - "doctrine/annotations": "^1.7 || ^2.0", - "friendsofphp/php-cs-fixer": "^2.17 || 3.62.0", - "phpstan/phpstan": "^1.6", - "phpunit/phpunit": ">=8", - "vimeo/psalm": "^4.23" - }, - "suggest": { - "doctrine/annotations": "^1.7 || ^2.0" - }, - "bin": [ - "bin/openapi" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" }, + "type": "library", "autoload": { "psr-4": { - "OpenApi\\": "src" + "voku\\": "src/voku/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "authors": [ { - "name": "Robert Allen", - "email": "zircote@gmail.com" - }, - { - "name": "Bob Fanger", - "email": "bfanger@gmail.com", - "homepage": "https://bfanger.nl" - }, - { - "name": "Martin Rademacher", - "email": "mano@radebatz.net", - "homepage": "https://radebatz.net" + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" } ], - "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", - "homepage": "https://github.com/zircote/swagger-php/", + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", "keywords": [ - "api", - "json", - "rest", - "service discovery" + "ascii", + "clean", + "php" ], "support": { - "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/4.11.1" + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" }, - "time": "2024-10-15T19:20:02+00:00" + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2024-11-21T01:49:47+00:00" } ], "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", + "composer-plugin-api": "^2.2", "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" }, "require-dev": { - "composer/composer": "*", + "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", @@ -6854,9 +7392,9 @@ "authors": [ { "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" }, { "name": "Contributors", @@ -6864,7 +7402,6 @@ } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", "keywords": [ "PHPCodeSniffer", "PHP_CodeSniffer", @@ -6885,22 +7422,41 @@ ], "support": { "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2023-01-05T11:28:13+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-11T04:32:07+00:00" }, { "name": "filp/whoops", - "version": "2.18.1", + "version": "2.18.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26" + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26", - "reference": "8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { @@ -6950,7 +7506,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.1" + "source": "https://github.com/filp/whoops/tree/2.18.4" }, "funding": [ { @@ -6958,7 +7514,7 @@ "type": "github" } ], - "time": "2025-06-03T18:56:14+00:00" + "time": "2025-08-08T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -7013,16 +7569,16 @@ }, { "name": "laravel/sail", - "version": "v1.43.1", + "version": "v1.52.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72" + "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/3e7d899232a8c5e3ea4fc6dee7525ad583887e72", - "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72", + "url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3", + "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3", "shasum": "" }, "require": { @@ -7035,7 +7591,7 @@ }, "require-dev": { "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^2.0" }, "bin": [ "bin/sail" @@ -7072,7 +7628,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2025-05-19T13:19:21+00:00" + "time": "2026-01-01T02:46:03+00:00" }, { "name": "mockery/mockery", @@ -7157,85 +7713,25 @@ }, "time": "2024-05-16T03:13:13+00:00" }, - { - "name": "myclabs/deep-copy", - "version": "1.13.1", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", - "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2025-04-29T12:36:36+00:00" - }, { "name": "nunomaduro/collision", - "version": "v8.8.0", + "version": "v8.8.3", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8" + "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/4cf9f3b47afff38b139fb79ce54fc71799022ce8", - "reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4", + "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4", "shasum": "" }, "require": { - "filp/whoops": "^2.18.0", - "nunomaduro/termwind": "^2.3.0", + "filp/whoops": "^2.18.1", + "nunomaduro/termwind": "^2.3.1", "php": "^8.2.0", - "symfony/console": "^7.2.5" + "symfony/console": "^7.3.0" }, "conflict": { "laravel/framework": "<11.44.2 || >=13.0.0", @@ -7243,15 +7739,15 @@ }, "require-dev": { "brianium/paratest": "^7.8.3", - "larastan/larastan": "^3.2", - "laravel/framework": "^11.44.2 || ^12.6", - "laravel/pint": "^1.21.2", - "laravel/sail": "^1.41.0", - "laravel/sanctum": "^4.0.8", + "larastan/larastan": "^3.4.2", + "laravel/framework": "^11.44.2 || ^12.18", + "laravel/pint": "^1.22.1", + "laravel/sail": "^1.43.1", + "laravel/sanctum": "^4.1.1", "laravel/tinker": "^2.10.1", - "orchestra/testbench-core": "^9.12.0 || ^10.1", - "pestphp/pest": "^3.8.0", - "sebastian/environment": "^7.2.0 || ^8.0" + "orchestra/testbench-core": "^9.12.0 || ^10.4", + "pestphp/pest": "^3.8.2 || ^4.0.0", + "sebastian/environment": "^7.2.1 || ^8.0" }, "type": "library", "extra": { @@ -7314,7 +7810,7 @@ "type": "patreon" } ], - "time": "2025-04-03T14:33:09+00:00" + "time": "2025-11-20T02:55:25+00:00" }, { "name": "phar-io/manifest", @@ -7436,35 +7932,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.9", + "version": "11.0.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", - "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.4.0", + "nikic/php-parser": "^5.7.0", "php": ">=8.2", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-text-template": "^4.0.1", "sebastian/code-unit-reverse-lookup": "^4.0.1", "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.0", + "sebastian/environment": "^7.2.1", "sebastian/lines-of-code": "^3.0.1", "sebastian/version": "^5.0.2", - "theseer/tokenizer": "^1.2.3" + "theseer/tokenizer": "^1.3.1" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^11.5.46" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -7502,15 +7998,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" } ], - "time": "2025-02-25T13:26:39+00:00" + "time": "2025-12-24T07:01:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -7759,16 +8267,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.21", + "version": "11.5.48", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "d565e2cdc21a7db9dc6c399c1fc2083b8010f289" + "reference": "fe3665c15e37140f55aaf658c81a2eb9030b6d89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d565e2cdc21a7db9dc6c399c1fc2083b8010f289", - "reference": "d565e2cdc21a7db9dc6c399c1fc2083b8010f289", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fe3665c15e37140f55aaf658c81a2eb9030b6d89", + "reference": "fe3665c15e37140f55aaf658c81a2eb9030b6d89", "shasum": "" }, "require": { @@ -7778,24 +8286,24 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.1", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.9", + "phpunit/php-code-coverage": "^11.0.12", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.1", + "sebastian/comparator": "^6.3.2", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.1", - "sebastian/exporter": "^6.3.0", + "sebastian/exporter": "^6.3.2", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", - "sebastian/type": "^5.1.2", + "sebastian/type": "^5.1.3", "sebastian/version": "^5.0.2", "staabm/side-effects-detector": "^1.0.5" }, @@ -7840,7 +8348,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.48" }, "funding": [ { @@ -7864,7 +8372,7 @@ "type": "tidelift" } ], - "time": "2025-05-21T12:35:00+00:00" + "time": "2026-01-16T16:26:27+00:00" }, { "name": "sebastian/cli-parser", @@ -8038,16 +8546,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.1", + "version": "6.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", + "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", "shasum": "" }, "require": { @@ -8106,15 +8614,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2025-03-07T06:57:01+00:00" + "time": "2025-08-10T08:07:46+00:00" }, { "name": "sebastian/complexity", @@ -8319,16 +8839,16 @@ }, { "name": "sebastian/exporter", - "version": "6.3.0", + "version": "6.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", "shasum": "" }, "require": { @@ -8342,7 +8862,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -8385,15 +8905,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2024-12-05T09:17:50+00:00" + "time": "2025-09-24T06:12:51+00:00" }, { "name": "sebastian/global-state", @@ -8631,23 +9163,23 @@ }, { "name": "sebastian/recursion-context", - "version": "6.0.2", + "version": "6.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { @@ -8683,28 +9215,40 @@ "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2024-07-03T05:10:34+00:00" + "time": "2025-08-13T04:42:22+00:00" }, { "name": "sebastian/type", - "version": "5.1.2", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", "shasum": "" }, "require": { @@ -8740,15 +9284,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "time": "2025-03-18T13:35:50+00:00" + "time": "2025-08-09T06:55:48+00:00" }, { "name": "sebastian/version", @@ -8806,37 +9362,32 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "65ff2489553b83b4597e89c3b8b721487011d186" + "reference": "0525c73950de35ded110cffafb9892946d7771b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/65ff2489553b83b4597e89c3b8b721487011d186", - "reference": "65ff2489553b83b4597e89c3b8b721487011d186", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0525c73950de35ded110cffafb9892946d7771b5", + "reference": "0525c73950de35ded110cffafb9892946d7771b5", "shasum": "" }, "require": { "ext-simplexml": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": ">=5.4.0" + "php": ">=7.2.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31" }, "bin": [ "bin/phpcbf", "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -8855,7 +9406,7 @@ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.", "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", @@ -8886,7 +9437,7 @@ "type": "thanks_dev" } ], - "time": "2025-05-11T03:36:00+00:00" + "time": "2025-11-10T16:43:36+00:00" }, { "name": "staabm/side-effects-detector", @@ -8940,18 +9491,94 @@ ], "time": "2024-10-20T05:08:20+00:00" }, + { + "name": "symfony/yaml", + "version": "v7.4.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-12-04T18:11:45+00:00" + }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -8980,7 +9607,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -8988,7 +9615,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], @@ -9003,5 +9630,5 @@ "platform-overrides": { "php": "8.3.6" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/config/app.php b/config/app.php index d5b82e2..0a8e9ba 100644 --- a/config/app.php +++ b/config/app.php @@ -146,6 +146,7 @@ Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, + \SocialiteProviders\Manager\ServiceProvider::class, /* * Package Service Providers... diff --git a/config/auth.php b/config/auth.php index e19e244..cb4b41d 100644 --- a/config/auth.php +++ b/config/auth.php @@ -50,7 +50,7 @@ ], 'admin' => [ 'driver' => 'session', - 'provider' => 'adldap' + 'provider' => 'users' ], ], @@ -81,14 +81,6 @@ 'driver' => 'eloquent', 'model' => App\Models\Client::class, ], - 'adldap' => [ - 'driver' => 'ldap', - 'model' => LdapRecord\Models\ActiveDirectory\User::class, - ], - // 'users' => [ - // 'driver' => 'database', - // 'table' => 'users', - // ], ], /* diff --git a/config/dataapi.php b/config/dataapi.php index 5e7f77e..6e466ca 100644 --- a/config/dataapi.php +++ b/config/dataapi.php @@ -6,7 +6,7 @@ 'yearquarter_max' => '9999', 'timezone' => 'America/Los_Angeles', 'common_course_char' => '&', - 'app_version' => '1.15.4', + 'app_version' => '1.16.0', 'admin_group' => env('ADMIN_GROUP', null), 'api_internal_domain' => env('API_INTERNAL_DOMAIN', 'internal.localhost.test'), ]; diff --git a/config/l5-swagger.php b/config/l5-swagger.php deleted file mode 100644 index 99cc0ac..0000000 --- a/config/l5-swagger.php +++ /dev/null @@ -1,239 +0,0 @@ - [ - /* - |-------------------------------------------------------------------------- - | Edit to set the api's title - |-------------------------------------------------------------------------- - */ - - 'title' => 'Bellevue College Data API', - ], - - 'routes' => [ - /* - |-------------------------------------------------------------------------- - | Route for accessing api documentation interface - |-------------------------------------------------------------------------- - */ - - 'api' => 'documentation', - - /* - |-------------------------------------------------------------------------- - | Route for accessing parsed swagger annotations. - |-------------------------------------------------------------------------- - */ - - 'docs' => 'api/v1/docs', - - /* - |-------------------------------------------------------------------------- - | Route for Oauth2 authentication callback. - |-------------------------------------------------------------------------- - */ - - 'oauth2_callback' => 'api/oauth2-callback', - - /* - |-------------------------------------------------------------------------- - | Middleware allows to prevent unexpected access to API documentation - |-------------------------------------------------------------------------- - */ - 'middleware' => [ - 'api' => [], - 'asset' => [], - 'docs' => [], - 'oauth2_callback' => [], - ], - ], - - 'paths' => [ - /* - |-------------------------------------------------------------------------- - | Absolute path to location where parsed swagger annotations will be stored - |-------------------------------------------------------------------------- - */ - - 'docs' => storage_path('api-docs'), - - /* - |-------------------------------------------------------------------------- - | File name of the generated json documentation file - |-------------------------------------------------------------------------- - */ - - 'docs_json' => 'api-docs.json', - - /* - |-------------------------------------------------------------------------- - | File name of the generated YAML documentation file - |-------------------------------------------------------------------------- - */ - - 'docs_yaml' => 'api-docs.yaml', - - /* - |-------------------------------------------------------------------------- - | Absolute paths to directory containing the swagger annotations are stored. - |-------------------------------------------------------------------------- - */ - - 'annotations' => [ - base_path('app'), - ], - - /* - |-------------------------------------------------------------------------- - | Absolute path to directory where to export views - |-------------------------------------------------------------------------- - */ - - 'views' => base_path('resources/views/vendor/l5-swagger'), - - /* - |-------------------------------------------------------------------------- - | Edit to set the api's base path - |-------------------------------------------------------------------------- - */ - - 'base' => env('L5_SWAGGER_BASE_PATH', null), - - /* - |-------------------------------------------------------------------------- - | Edit to set path where swagger ui assets should be stored - |-------------------------------------------------------------------------- - */ - - 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), - - /* - |-------------------------------------------------------------------------- - | Absolute path to directories that you would like to exclude from swagger generation - |-------------------------------------------------------------------------- - */ - - 'excludes' => [], - ], - - /* - |-------------------------------------------------------------------------- - | API security definitions. Will be generated into documentation file. - |-------------------------------------------------------------------------- - */ - 'security' => [ - /* - |-------------------------------------------------------------------------- - | Examples of Security definitions - |-------------------------------------------------------------------------- - */ - /* - 'api_key_security_example' => [ // Unique name of security - 'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". - 'description' => 'A short description for security scheme', - 'name' => 'api_key', // The name of the header or query parameter to be used. - 'in' => 'header', // The location of the API key. Valid values are "query" or "header". - ], - 'oauth2_security_example' => [ // Unique name of security - 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". - 'description' => 'A short description for oauth2 security scheme.', - 'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode". - 'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode) - //'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode) - 'scopes' => [ - 'read:projects' => 'read your projects', - 'write:projects' => 'modify projects in your account', - ] - ], - */ - - /* Open API 3.0 support - 'passport' => [ // Unique name of security - 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". - 'description' => 'Laravel passport oauth2 security.', - 'in' => 'header', - 'scheme' => 'https', - 'flows' => [ - "password" => [ - "authorizationUrl" => config('app.url') . '/oauth/authorize', - "tokenUrl" => config('app.url') . '/oauth/token', - "refreshUrl" => config('app.url') . '/token/refresh', - "scopes" => [] - ], - ], - ], - */ - ], - - /* - |-------------------------------------------------------------------------- - | Turn this off to remove swagger generation on production - |-------------------------------------------------------------------------- - */ - - 'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', false), - - /* - |-------------------------------------------------------------------------- - | Turn this on to generate a copy of documentation in yaml format - |-------------------------------------------------------------------------- - */ - - 'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false), - - /* - |-------------------------------------------------------------------------- - | Edit to set the swagger version number - |-------------------------------------------------------------------------- - */ - - 'swagger_version' => env('SWAGGER_VERSION', '3.0'), - - /* - |-------------------------------------------------------------------------- - | Edit to trust the proxy's ip address - needed for AWS Load Balancer - |-------------------------------------------------------------------------- - */ - - 'proxy' => false, - - /* - |-------------------------------------------------------------------------- - | Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle. - | See more at: https://github.com/swagger-api/swagger-ui#configs-plugin - |-------------------------------------------------------------------------- - */ - - 'additional_config_url' => null, - - /* - |-------------------------------------------------------------------------- - | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), - | 'method' (sort by HTTP method). - | Default is the order returned by the server unchanged. - |-------------------------------------------------------------------------- - */ - - 'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null), - - /* - |-------------------------------------------------------------------------- - | Uncomment to pass the validatorUrl parameter to SwaggerUi init on the JS - | side. A null value here disables validation. - |-------------------------------------------------------------------------- - */ - - 'validator_url' => null, - - /* - |-------------------------------------------------------------------------- - | Uncomment to add constants which can be used in annotations - |-------------------------------------------------------------------------- - */ - 'constants' => [ - 'PUBLIC_URL' => env('APP_URL', 'https://www2.bellevuecollege.edu/data'), - 'PRIVATE_URL' => env('API_INTERNAL_DOMAIN', 'no.bellevuecollege.edu/data'), - 'APP_VERSION' => config('dataapi.app_version') - ], -]; diff --git a/config/ldap.php b/config/ldap.php deleted file mode 100644 index ac6f573..0000000 --- a/config/ldap.php +++ /dev/null @@ -1,81 +0,0 @@ - env('ADLDAP_CONNECTION', 'default'), - - /* - |-------------------------------------------------------------------------- - | LDAP Connections - |-------------------------------------------------------------------------- - | - | Below you may configure each LDAP connection your application requires - | access to. Be sure to include a valid base DN - otherwise you may - | not receive any results when performing LDAP search operations. - | - */ - - 'connections' => [ - - 'default' => [ - 'hosts' => [env('ADLDAP_CONTROLLERS', '127.0.0.1')], - 'username' => env('ADLDAP_ADMIN_USERNAME', 'cn=user,dc=local,dc=com'), - 'password' => env('ADLDAP_ADMIN_PASSWORD', 'secret'), - 'port' => env('ADLDAP_PORT', 389), - 'base_dn' => env('ADLDAP_BASEDN', 'dc=local,dc=com'), - 'timeout' => env('ADLDAP_TIMEOUT', 5), - 'use_ssl' => env('ADLDAP_USE_SSL', false), - 'use_tls' => env('ADLDAP_USE_TLS', false), - 'use_sasl' => env('ADLDAP_SASL', false), - 'sasl_options' => [ - // 'mech' => 'GSSAPI', - ], - ], - - ], - - /* - |-------------------------------------------------------------------------- - | LDAP Logging - |-------------------------------------------------------------------------- - | - | When LDAP logging is enabled, all LDAP search and authentication - | operations are logged using the default application logging - | driver. This can assist in debugging issues and more. - | - */ - - 'logging' => [ - 'enabled' => env('ADLDAP_LOGGING', false), - 'channel' => env('LOG_CHANNEL', 'stack'), - 'level' => env('LOG_LEVEL', 'info'), - ], - - /* - |-------------------------------------------------------------------------- - | LDAP Cache - |-------------------------------------------------------------------------- - | - | LDAP caching enables the ability of caching search results using the - | query builder. This is great for running expensive operations that - | may take many seconds to complete, such as a pagination request. - | - */ - - 'cache' => [ - 'enabled' => env('ADLDAP_CACHE', false), - 'driver' => env('CACHE_DRIVER', 'file'), - ], - -]; diff --git a/config/ldap_auth.php b/config/ldap_auth.php deleted file mode 100644 index de07c5c..0000000 --- a/config/ldap_auth.php +++ /dev/null @@ -1,341 +0,0 @@ - env('ADLDAP_CONNECTION', 'default'), - - /* - |-------------------------------------------------------------------------- - | Provider - |-------------------------------------------------------------------------- - | - | The LDAP authentication provider to use depending - | if you require database synchronization. - | - | For synchronizing LDAP users to your local applications database, use the provider: - | - | Adldap\Laravel\Auth\DatabaseUserProvider::class - | - | Otherwise, if you just require LDAP authentication, use the provider: - | - | Adldap\Laravel\Auth\NoDatabaseUserProvider::class - | - */ - - 'provider' => Adldap\Laravel\Auth\NoDatabaseUserProvider::class, - - /* - |-------------------------------------------------------------------------- - | Model - |-------------------------------------------------------------------------- - | - | The model to utilize for authentication and importing. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - // 'model' => App\User::class, - - /* - |-------------------------------------------------------------------------- - | Rules - |-------------------------------------------------------------------------- - | - | Rules allow you to control user authentication requests depending on scenarios. - | - | You can create your own rules and insert them here. - | - | All rules must extend from the following class: - | - | Adldap\Laravel\Validation\Rules\Rule - | - */ - - 'rules' => [ - - // Denys deleted users from authenticating. - - Adldap\Laravel\Validation\Rules\DenyTrashed::class, - - // Allows only manually imported users to authenticate. - - // Adldap\Laravel\Validation\Rules\OnlyImported::class, - - ], - - /* - |-------------------------------------------------------------------------- - | Scopes - |-------------------------------------------------------------------------- - | - | Scopes allow you to restrict the LDAP query that locates - | users upon import and authentication. - | - | All scopes must implement the following interface: - | - | Adldap\Laravel\Scopes\ScopeInterface - | - */ - - 'scopes' => [ - - // Only allows users with a user principal name to authenticate. - // Suitable when using ActiveDirectory. - Adldap\Laravel\Scopes\UpnScope::class, - - // Only allows users with a uid to authenticate. - // Suitable when using OpenLDAP. - // Adldap\Laravel\Scopes\UidScope::class, - - // Only allow developers to log in. - App\Scopes\AdminGroupScope::class, - ], - - 'identifiers' => [ - - /* - |-------------------------------------------------------------------------- - | LDAP - |-------------------------------------------------------------------------- - | - | Locate Users By: - | - | This value is the users attribute you would like to locate LDAP - | users by in your directory. - | - | For example, using the default configuration below, if you're - | authenticating users with an email address, your LDAP server - | will be queried for a user with the a `userprincipalname` - | equal to the entered email address. - | - | Bind Users By: - | - | This value is the users attribute you would - | like to use to bind to your LDAP server. - | - | For example, when a user is located by the above attribute, - | the users attribute you specify below will be used as - | the 'username' to bind to your LDAP server. - | - | This is usually their distinguished name. - | - */ - - 'ldap' => [ - - 'locate_users_by' => 'samaccountname', - - 'bind_users_by' => 'distinguishedname', - - ], - - 'database' => [ - - /* - |-------------------------------------------------------------------------- - | GUID Column - |-------------------------------------------------------------------------- - | - | The value of this option is the database column that will contain the - | LDAP users global identifier. This column does not need to be added - | to the sync attributes below. It is synchronized automatically. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - 'guid_column' => 'objectguid', - - /* - |-------------------------------------------------------------------------- - | Username Column - |-------------------------------------------------------------------------- - | - | The value of this option is the database column that contains your - | users login username. - | - | This column must be added to your sync attributes below to be - | properly synchronized. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - 'username_column' => 'samaccountname', - - ], - - /* - |-------------------------------------------------------------------------- - | Windows Authentication Middleware (SSO) - |-------------------------------------------------------------------------- - | - | Local Users By: - | - | This value is the users attribute you would like to locate LDAP - | users by in your directory. - | - | For example, if 'samaccountname' is the value, then your LDAP server is - | queried for a user with the 'samaccountname' equal to the value of - | $_SERVER['AUTH_USER']. - | - | If a user is found, they are imported (if using the DatabaseUserProvider) - | into your local database, then logged in. - | - | Server Key: - | - | This value represents the 'key' of the $_SERVER - | array to pull the users account name from. - | - | For example, $_SERVER['AUTH_USER']. - | - */ - - 'windows' => [ - - 'locate_users_by' => 'samaccountname', - - 'server_key' => 'AUTH_USER', - - ], - - ], - - 'passwords' => [ - - /* - |-------------------------------------------------------------------------- - | Password Sync - |-------------------------------------------------------------------------- - | - | The password sync option allows you to automatically synchronize users - | LDAP passwords to your local database. These passwords are hashed - | natively by Laravel using the Hash::make() method. - | - | Enabling this option would also allow users to login to their accounts - | using the password last used when an LDAP connection was present. - | - | If this option is disabled, the local database account is applied a - | random 16 character hashed password upon first login, and will - | lose access to this account upon loss of LDAP connectivity. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - 'sync' => env('ADLDAP_PASSWORD_SYNC', false), - - /* - |-------------------------------------------------------------------------- - | Column - |-------------------------------------------------------------------------- - | - | This is the column of your users database table - | that is used to store passwords. - | - | Set this to `null` if you do not have a password column. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - 'column' => 'password', - - ], - - /* - |-------------------------------------------------------------------------- - | Login Fallback - |-------------------------------------------------------------------------- - | - | The login fallback option allows you to login as a user located in the - | local database if active directory authentication fails. - | - | Set this to true if you would like to enable it. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - 'login_fallback' => env('ADLDAP_LOGIN_FALLBACK', false), - - /* - |-------------------------------------------------------------------------- - | Sync Attributes - |-------------------------------------------------------------------------- - | - | Attributes specified here will be added / replaced on the user model - | upon login, automatically synchronizing and keeping the attributes - | up to date. - | - | The array key represents the users Laravel model key, and - | the value represents the users LDAP attribute. - | - | You **must** include the users login attribute here. - | - | This option is only applicable to the DatabaseUserProvider. - | - */ - - 'sync_attributes' => [ - - 'email' => 'userprincipalname', - - 'name' => 'cn', - - ], - - /* - |-------------------------------------------------------------------------- - | Logging - |-------------------------------------------------------------------------- - | - | User authentication attempts will be logged using Laravel's - | default logger if this setting is enabled. - | - | No credentials are logged, only usernames. - | - | This is usually stored in the '/storage/logs' directory - | in the root of your application. - | - | This option is useful for debugging as well as auditing. - | - | You can freely remove any events you would not like to log below, - | as well as use your own listeners if you would prefer. - | - */ - - 'logging' => [ - - 'enabled' => env('ADLDAP_LOGGING', true), - - 'events' => [ - - \Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class, - \Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class, - \Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class, - \Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class, - \Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class, - \Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class, - \Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class, - \Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class, - \Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class, - \Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class, - \Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class, - - ], - ], - -]; diff --git a/config/permissions.php b/config/permissions.php new file mode 100644 index 0000000..dc62218 --- /dev/null +++ b/config/permissions.php @@ -0,0 +1,9 @@ + 'Read Student Data', + 'read_employee_data' => 'Read Employee Data', + 'read_directory_data' => 'Read Directory Data', + 'write_transactions' => 'Write Transactions', + 'write_user_questions' => 'Write User Questions to BrutusBot tables', +]; \ No newline at end of file diff --git a/config/scramble.php b/config/scramble.php new file mode 100644 index 0000000..6d870d5 --- /dev/null +++ b/config/scramble.php @@ -0,0 +1,143 @@ + 'api', + + /* + * Your API domain. By default, app domain is used. This is also a part of the default API routes + * matcher, so when implementing your own, make sure you use this config if needed. + */ + 'api_domain' => null, + + /* + * The path where your OpenAPI specification will be exported. + */ + 'export_path' => 'api.json', + + 'info' => [ + /* + * API version. + */ + 'version' => env('API_VERSION', '0.0.1'), + + /* + * Description rendered on the home page of the API documentation (`/docs/api`). + */ + 'description' => 'The Bellevue College Data API allows for interaction with some Bellevue College data via RESTful methods.', + ], + + /* + * Customize Stoplight Elements UI + */ + 'ui' => [ + /* + * Define the title of the documentation's website. App name is used when this config is `null`. + */ + 'title' => 'Bellevue College Data API', + + /* + * Define the theme of the documentation. Available options are `light`, `dark`, and `system`. + */ + 'theme' => 'system', + + /* + * Hide the `Try It` feature. Enabled by default. + */ + 'hide_try_it' => false, + + /* + * Hide the schemas in the Table of Contents. Enabled by default. + */ + 'hide_schemas' => false, + + /* + * URL to an image that displays as a small square logo next to the title, above the table of contents. + */ + 'logo' => '', + + /* + * Use to fetch the credential policy for the Try It feature. Options are: omit, include (default), and same-origin + */ + 'try_it_credentials_policy' => 'include', + + /* + * There are three layouts for Elements: + * - sidebar - (Elements default) Three-column design with a sidebar that can be resized. + * - responsive - Like sidebar, except at small screen sizes it collapses the sidebar into a drawer that can be toggled open. + * - stacked - Everything in a single column, making integrations with existing websites that have their own sidebar or other columns already. + */ + 'layout' => 'responsive', + ], + + /* + * The list of servers of the API. By default, when `null`, server URL will be created from + * `scramble.api_path` and `scramble.api_domain` config variables. When providing an array, you + * will need to specify the local server URL manually (if needed). + * + * Example of non-default config (final URLs are generated using Laravel `url` helper): + * + * ```php + * 'servers' => [ + * 'Live' => 'api', + * 'Prod' => 'https://scramble.dedoc.co/api', + * ], + * ``` + */ + 'servers' => [ + 'Main API - Use this by default' => $appUrl . '/api', + 'Internal API - /internal/ prefix' => $scheme.'://'.$internalDomain.$subdirPrefix.'/api', + ], + + /** + * Determines how Scramble stores the descriptions of enum cases. + * Available options: + * - 'description' – Case descriptions are stored as the enum schema's description using table formatting. + * - 'extension' – Case descriptions are stored in the `x-enumDescriptions` enum schema extension. + * + * @see https://redocly.com/docs-legacy/api-reference-docs/specification-extensions/x-enum-descriptions + * - false - Case descriptions are ignored. + */ + 'enum_cases_description_strategy' => 'description', + + /** + * Determines how Scramble stores the names of enum cases. + * Available options: + * - 'names' – Case names are stored in the `x-enumNames` enum schema extension. + * - 'varnames' - Case names are stored in the `x-enum-varnames` enum schema extension. + * - false - Case names are not stored. + */ + 'enum_cases_names_strategy' => false, + + /** + * When Scramble encounters deep objects in query parameters, it flattens the parameters so the generated + * OpenAPI document correctly describes the API. Flattening deep query parameters is relevant until + * OpenAPI 3.2 is released and query string structure can be described properly. + * + * For example, this nested validation rule describes the object with `bar` property: + * `['foo.bar' => ['required', 'int']]`. + * + * When `flatten_deep_query_parameters` is `true`, Scramble will document the parameter like so: + * `{"name":"foo[bar]", "schema":{"type":"int"}, "required":true}`. + * + * When `flatten_deep_query_parameters` is `false`, Scramble will document the parameter like so: + * `{"name":"foo", "schema": {"type":"object", "properties":{"bar":{"type": "int"}}, "required": ["bar"]}, "required":true}`. + */ + 'flatten_deep_query_parameters' => true, + + 'middleware' => [ + 'web', + ], + + 'extensions' => [], +]; diff --git a/config/services.php b/config/services.php index aa1f7f8..cdfcfcd 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,12 @@ 'secret' => env('STRIPE_SECRET'), ], + 'azure' => [ + 'client_id' => env('AZURE_CLIENT_ID'), + 'client_secret' => env('AZURE_CLIENT_SECRET'), + 'redirect' => env('AZURE_REDIRECT_URI'), + 'tenant' => env('AZURE_TENANT_ID'), + 'proxy' => env('AZURE_PROXY'), + ], + ]; diff --git a/database/migrations/2025_11_17_230351_create_users_table.php b/database/migrations/2025_11_17_230351_create_users_table.php new file mode 100644 index 0000000..13c0cc6 --- /dev/null +++ b/database/migrations/2025_11_17_230351_create_users_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('azure_id')->unique(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + } +}; diff --git a/database/migrations/2025_11_18_163700_add_permissions_to_clients_table.php b/database/migrations/2025_11_18_163700_add_permissions_to_clients_table.php new file mode 100644 index 0000000..a713f2e --- /dev/null +++ b/database/migrations/2025_11_18_163700_add_permissions_to_clients_table.php @@ -0,0 +1,28 @@ +table('Clients', function (Blueprint $table) { + $table->json('permissions')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::connection('da')->table('Clients', function (Blueprint $table) { + $table->dropColumn('permissions'); + }); + } +}; diff --git a/database/migrations/2025_11_18_215051_create_cache_table.php b/database/migrations/2025_11_18_215051_create_cache_table.php new file mode 100644 index 0000000..b5a7b12 --- /dev/null +++ b/database/migrations/2025_11_18_215051_create_cache_table.php @@ -0,0 +1,35 @@ +create('cache', function (Blueprint $table) { + $table->string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::connection('da')->create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::connection('da')->dropIfExists('cache'); + Schema::connection('da')->dropIfExists('cache_locks'); + } +}; diff --git a/database/migrations/2025_11_18_215135_create_sessions_table.php b/database/migrations/2025_11_18_215135_create_sessions_table.php new file mode 100644 index 0000000..0fe0495 --- /dev/null +++ b/database/migrations/2025_11_18_215135_create_sessions_table.php @@ -0,0 +1,31 @@ +create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->unsignedBigInteger('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::connection('da')->dropIfExists('sessions'); + } +}; diff --git a/database/migrations/2025_12_19_172332_add_created_by_to_clients_table.php b/database/migrations/2025_12_19_172332_add_created_by_to_clients_table.php new file mode 100644 index 0000000..7af7dd4 --- /dev/null +++ b/database/migrations/2025_12_19_172332_add_created_by_to_clients_table.php @@ -0,0 +1,32 @@ +foreignId('created_by') + ->nullable() + ->constrained('users') + ->nullOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropForeign(['created_by']); + $table->dropColumn('created_by'); + }); + } +}; diff --git a/docker-compose.yml b/docker-compose.yml index 1096ced..f2c7b6d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,7 @@ services: ports: - '${APP_PORT:-80}:80' - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' + - '443:443' # SSL port environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 @@ -19,6 +20,8 @@ services: XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' volumes: - '.:/var/www/html' + - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf # Nginx configuration + - ./docker/nginx/ssl:/etc/nginx/ssl # SSL certificates networks: - sail networks: diff --git a/docker/8.3/Dockerfile b/docker/8.3/Dockerfile index 802e986..8b723dc 100644 --- a/docker/8.3/Dockerfile +++ b/docker/8.3/Dockerfile @@ -19,7 +19,8 @@ RUN apt-get update \ && echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \ && apt-get update \ && apt-get install -y php8.3-cli php8.3-dev \ - php8.3-pgsql php8.3-sqlite3 php8.3-gd \ + nginx \ + php8.3-pgsql php8.3-sqlite3 php8.3-gd php8.3-fpm \ php8.3-curl \ php8.3-imap php8.3-mysql php8.3-mbstring \ php8.3-xml php8.3-zip php8.3-bcmath php8.3-soap \ diff --git a/docker/8.3/supervisord.conf b/docker/8.3/supervisord.conf index 9d28479..215ab1f 100644 --- a/docker/8.3/supervisord.conf +++ b/docker/8.3/supervisord.conf @@ -4,10 +4,21 @@ user=root logfile=/var/log/supervisor/supervisord.log pidfile=/var/run/supervisord.pid -[program:php] -command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80 -user=sail -environment=LARAVEL_SAIL="1" +[program:php-fpm] +command=/usr/sbin/php-fpm8.3 -F +user=root +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +user=root +autostart=true +autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf new file mode 100644 index 0000000..99bb282 --- /dev/null +++ b/docker/nginx/nginx.conf @@ -0,0 +1,64 @@ +user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Main domain: data-api.test + server { + listen 80; + listen 443 ssl; + server_name data-api.test; + + ssl_certificate /etc/nginx/ssl/data-api.crt; + ssl_certificate_key /etc/nginx/ssl/data-api.key; + + root /var/www/html/public; + index index.php index.html; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location ~ \.php$ { + fastcgi_pass unix:/run/php/php8.3-fpm.sock; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + include fastcgi_params; + } + } + + # Subdomain: no.data-api.test + server { + listen 80; + listen 443 ssl; + server_name no.data-api.test; + + ssl_certificate /etc/nginx/ssl/data-api.crt; + ssl_certificate_key /etc/nginx/ssl/data-api.key; + + root /var/www/html/public; + index index.php index.html; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location ~ \.php$ { + fastcgi_pass unix:/run/php/php8.3-fpm.sock; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + include fastcgi_params; + } + } + + sendfile on; + keepalive_timeout 65; +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1a01f0a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "html", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/readme.md b/readme.md index 29e0da7..758864b 100644 --- a/readme.md +++ b/readme.md @@ -2,14 +2,11 @@ The Data API is a RESTful, primarily read-only web service for accessing Bellevue College data in JSON format. -## API Endpoints 🌐 - -### OpenAPI 3.0 Documentation +## Documentation Endpoint 📚 -As endpoints are added or updated, OpenAPI documentation is being added. +- `docs/api` - The documentation endpoint for the Data API (thanks to [Scramble](https://scramble.dedoc.co/)) -- [JSON OpenAPI Documentation Endpoint](https://www2.bellevuecollege.edu/data/api/v1/docs/) -- [Swagger Docs for API (in progress)](https://www2.bellevuecollege.edu/data/documentation/) +## API Endpoints 🌐 ### Class/course data 🎓 @@ -64,11 +61,6 @@ It is only available on the internal subdomain. For explanation on terminology/objects used in the DataAPI, [refer to the terminology documentation](terminology.md). -API Documentation is being written through [L5-Swagger](https://github.com/DarkaOnLine/L5-Swagger). Run the following to compile: - -```bash -php artisan l5-swagger:generate -``` ## Development Environment @@ -76,6 +68,9 @@ Data API uses [Laravel Sail](https://laravel.com/docs/10.x/sail) for a local dev With [Docker](https://www.docker.com/) installed, run `./vendor/bin/sail up` to build and start the VM. +Alternativly, you can use Podman instead of docker with some additional configuration; good info on this +in [this medium article](https://medium.com/mamitech/the-shortest-path-to-replace-docker-with-podman-for-laravel-sail-b02d184a1b72) + Once Sail informs you of the IP address it is using, add the following entries to your hosts file: ``` # Laravel Sail @@ -83,6 +78,15 @@ Once Sail informs you of the IP address it is using, add the following entries t 0.0.0.0 no.data-api.test ``` +To support SSL, you'll also need to generate a certificate and key. +```bash +openssl req -newkey rsa:2048 -nodes \ + -keyout docker/nginx/ssl/data-api.key \ + -x509 -days 365 \ + -out docker/nginx/ssl/data-api.crt \ + -subj "/CN=*.data-api.test" +``` + ### Upgrade Considerations When upgrading to a new version of PHP, the Dockerfile may need to be updated as well. @@ -93,6 +97,16 @@ Lines 28 and 46 of `/docker/8.1/Dockerfile` were added in order to add SQL Serve | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [![Build status](https://dev.azure.com/bcintegration/data-api/_apis/build/status/data-api-master)](https://dev.azure.com/bcintegration/data-api/_build/latest?definitionId=20) | [![Build status](https://dev.azure.com/bcintegration/data-api/_apis/build/status/data-api-dev)](https://dev.azure.com/bcintegration/data-api/_build/latest?definitionId=19) | +## Configuration 🛠️ + +### Azure Entra ID +Make sure to set the following environment variables: + +- `AZURE_CLIENT_ID` - The client ID of the Azure Entra ID application +- `AZURE_CLIENT_SECRET` - The client secret of the Azure Entra ID application +- `AZURE_TENANT_ID` - The tenant ID of the Azure Entra ID application +- `AZURE_REDIRECT_URI` - The redirect URI of the Azure Entra ID application (e.g. `https://no.data-api.test/admin/login/callback`) + ## The BadgeZone 💫 [![emoji-log](https://cdn.rawgit.com/ahmadawais/stuff/ca97874/emoji-log/flat-round.svg)](https://github.com/ahmadawais/Emoji-Log/) diff --git a/resources/views/admin/addclient.blade.php b/resources/views/admin/addclient.blade.php index b9f54c9..416f8f1 100644 --- a/resources/views/admin/addclient.blade.php +++ b/resources/views/admin/addclient.blade.php @@ -4,14 +4,14 @@ @section('content') -

Add Client

+

Add Client

@if ( !empty($success) && $success )
New client {{$clientname}} added successfully. The client will use the following ID and key to authenticate against the API. Note the key now as it is not retrievable.
@endif @@ -24,17 +24,36 @@ @endif -
- @csrf -
- - -
-
- - -
- -
+ @if ( empty($success) ) + +
+ @csrf +
+ + +
+
+ + +
+
+
+ Permissions + + @if (isset($permissions) && count($permissions) > 0) + @foreach($permissions as $permissionName => $permissionDescription) +
+ + +
+ @endforeach + @endif +
+
+ +
+ @endif @endsection \ No newline at end of file diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 2c2a362..62172ec 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -15,28 +15,83 @@ {{ session('error') }} @endif - - - - - - - - - - @foreach ($data as $client) - - - - - - @endforeach - -
Client nameClient id
{{ $client->clientname }}{{ $client->clientid }} - Delete -
+
+ + + + + + + + + + + @foreach ($data as $client) + + + + + + + @endforeach + +
Client nameClient idPermissionsActions
{{ $client->clientname }}{{ $client->clientid }} + @if (isset($client->permissions) && count($client->permissions) > 0) + @foreach($client->permissions as $permission ) + {{ $permission }} + @endforeach + @else + No permissions + @endif + +
+ Edit + Delete +
+
+

Add new client

+ + + + + + @endsection \ No newline at end of file diff --git a/resources/views/admin/updateclient.blade.php b/resources/views/admin/updateclient.blade.php new file mode 100644 index 0000000..5f825ae --- /dev/null +++ b/resources/views/admin/updateclient.blade.php @@ -0,0 +1,61 @@ +@extends('layouts.admin') + +@section('title', 'Edit Client') + +@section('content') + +

Edit Client

+ @if (session('success')) +
+ {{ session('success') }} +
+ @endif + @if (session('error')) +
+ {{ session('error') }} +
+ @endif + +
+ @csrf + @method('PUT') +
+ + +
+ +
+ + +
+ +
+
+ Permissions + @if (isset($permissions) && count($permissions) > 0) + @foreach($permissions as $permissionName => $permissionDescription) +
+ permissions ?? [] )) checked @endif> + +
+ @endforeach + @endif +
+
+ +
+ + Cancel +
+
+ + +@endsection \ No newline at end of file diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php index b498e70..c761076 100644 --- a/resources/views/layouts/admin.blade.php +++ b/resources/views/layouts/admin.blade.php @@ -9,13 +9,10 @@ DataAPI Admin - @yield('title') - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - diff --git a/routes/api.php b/routes/api.php index 8d209fe..3258047 100644 --- a/routes/api.php +++ b/routes/api.php @@ -29,8 +29,8 @@ 'prefix' => 'v1' ], function ($router) { - Route::get('internal/employee/{username}', 'EmployeeController@getEmployeeByUsername'); - Route::get('internal/student/{username}','StudentController@getStudentByUsername'); + Route::get('internal/employee/{username}', 'EmployeeController@getEmployeeByUsername')->middleware('can:read_employee_data'); + Route::get('internal/student/{username}','StudentController@getStudentByUsername')->middleware('can:read_student_data'); }); @@ -42,7 +42,7 @@ ], function ($router) { Route::post('internal/auth/login', [ - 'as' => 'login', 'uses' => 'AuthController@login' + 'as' => 'login', 'uses' => 'AuthController@internalLogin', 'name' => 'internal.auth.login' ]); }); @@ -54,7 +54,9 @@ **/ Route::prefix('v1')->middleware([ 'auth.basic:api-basic,clientid', - 'throttle:60,1' + 'guard.api-basic', + 'throttle:60,1', + 'can:write_transactions' ])->group(function () { Route::prefix('forms/pci')->group(function () { @@ -80,8 +82,6 @@ }); }); - -/* Additions by John begin */ /** * Copilot Endpoints * @@ -89,7 +89,9 @@ **/ Route::prefix('v1')->middleware([ 'auth.basic:api-basic,clientid', - 'throttle:60,1' + 'guard.api-basic', + 'throttle:60,1', + 'can:write_user_questions' ])->group(function () { Route::prefix('copilot')->group(function () { @@ -101,20 +103,20 @@ }); }); -/* Additions by John end */ /** * Protected Endpoints Available on Public Domain */ -Route::group(['middleware' => ['auth:api', 'throttle:180,1'], 'prefix' => 'v1'], function ($router) { +Route::group(['middleware' => [ + 'auth:api', + 'throttle:180,1', + 'can:read_directory_data', +], 'prefix' => 'v1'], function ($router) { Route::prefix('directory')->group(function () { - Route::get('employee/{username}', 'EmployeeController@getDirectoryEmployeeByUsername'); + Route::get('employee/{username}', 'EmployeeController@getDirectoryEmployeeByUsername')->middleware('can:read_directory_data'); Route::get('employees', 'EmployeeController@getDirectoryEmployees')->middleware('throttle:60,1'); - - /* Additions by John begin */ Route::get('employees/{substring}', 'EmployeeController@getDirectoryEmployeeDisplayNameSubstringSearch')->middleware('throttle:60,1'); - /* Additions by John end */ }); }); @@ -124,7 +126,7 @@ ])->group(function () { Route::post('auth/login', [ - 'as' => 'login', 'uses' => 'AuthController@login' + 'as' => 'login', 'uses' => 'AuthController@publicLogin', 'name' => 'auth.login' ]); Route::get('subject/{slug}','SubjectController@getSubject'); @@ -145,18 +147,10 @@ Route::get('schedules/{psclassid}', 'ClassScheduleController@getClassSchedules'); - /* Additions by John begin */ // This is for Copilot Studio: Get an array of links and descriptions based on a provided SourceArea value Route::get('linksfound/{sourcearea}', 'LinkFoundController@getLinksBySourceArea'); // This is for Copilot Studio: Get a count of the links based on a provided SourceArea value Route::get('linkscount/{sourcearea}', 'LinkFoundController@getLinkCountBySourceArea'); - /* Additions by John end */ - //API endpoints specific to ModoLabs requirements - /*Route::get('catalog/terms', 'YearQuarterController@getViewableYearQuarters'); - Route::get('catalog/terms/{yqrid}', 'YearQuarterController@getYearQuarter'); - Route::get('catalog/catalogAreas/{yqrid}', 'SubjectController@getSubjectsByYearQuarter'); - Route::get('catalog/{yqrid}/{subjectid}', 'CourseYearQuarterController@getCourseYearQuartersBySubject'); - Route::get('catalog/{yqrid}/{subjectid}/{coursenum}', 'CourseYearQuarterController@getCourseYearQuarter');*/ }); diff --git a/routes/web.php b/routes/web.php index 891d8c5..472effd 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,4 +1,7 @@ group( function( $router ) { Route::name('admin.')->group(function () { - Route::get('admin/login', 'AdminController@loginShow')->name('login'); - Route::post('admin/login', 'AdminController@loginPost'); + // redirect to azure login route + //Route::get('admin/login', 'AdminController@loginShow')->name('login'); + //Route::post('admin/login', 'AdminController@loginPost'); + Route::get('admin/login', function () { + return Socialite::driver('azure')->redirect(); + }); + + Route::get('admin/login/callback', function () { + $azureUser = Socialite::driver('azure')->user(); + + $user = User::updateOrCreate([ + 'azure_id' => $azureUser->id, + ], [ + 'name' => $azureUser->name, + 'email' => $azureUser->email, + ]); + + Auth::guard('admin')->login($user); + return redirect()->route('admin.index'); + }); Route::middleware(['auth:admin'])->group(function () { Route::get('admin', 'AdminController@index')->name('index'); Route::get('admin/client/add', 'AdminController@addClientShow')->name('client.add'); Route::post('admin/client/add', 'AdminController@addClientPost')->name('client.add'); - Route::get('admin/client/{id}/delete', 'AdminController@deleteClient')->name('client.delete'); + Route::delete('admin/client/{id}/delete', 'AdminController@deleteClient')->name('client.delete'); + Route::get('admin/client/{id}/update', 'AdminController@updateClient')->name('client.update'); + Route::put('admin/client/{id}/update', 'AdminController@updateClientPut')->name('client.update'); Route::get('admin/logout', 'AdminController@logout')->name('logout'); });