diff --git a/.idea/leantime-oss.iml b/.idea/leantime-oss.iml index 83f6ab48d4..cb43a9b886 100644 --- a/.idea/leantime-oss.iml +++ b/.idea/leantime-oss.iml @@ -111,7 +111,6 @@ - @@ -119,37 +118,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.idea/php.xml b/.idea/php.xml index b54747a895..f38e4d0e47 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -178,7 +178,6 @@ - @@ -201,37 +200,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/Command/CheckTranslations.php b/app/Command/CheckTranslations.php index 336f143a5a..3ff1e46534 100644 --- a/app/Command/CheckTranslations.php +++ b/app/Command/CheckTranslations.php @@ -4,8 +4,8 @@ use Illuminate\Console\Command; use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Finder\Finder; use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Finder\Finder; #[AsCommand( name: 'translations:check-unused', @@ -21,6 +21,7 @@ class CheckTranslations extends Command protected $description = 'Scan codebase for unused translation strings'; protected $translations = []; + protected $usedTranslations = []; public function handle() @@ -42,8 +43,9 @@ public function handle() private function parseLanguageFile(): void { $langFile = app_path('Language/en-US.ini'); - if (!file_exists($langFile)) { - $this->error('Language file not found: ' . $langFile); + if (! file_exists($langFile)) { + $this->error('Language file not found: '.$langFile); + return; } @@ -60,10 +62,10 @@ private function scanFiles(): void $excludeDirs = explode(',', $this->option('exclude')); if ($this->option('debug')) { - $this->info('Excluding directories: ' . implode(', ', $excludeDirs)); + $this->info('Excluding directories: '.implode(', ', $excludeDirs)); } - $finder = new Finder(); + $finder = new Finder; $finder->files() ->in(app_path()) ->name('*.php') @@ -97,10 +99,10 @@ private function scanFileForTranslations($file): void preg_quote($key, '/'), // Direct key usage preg_quote("'$key'", '/'), // Single quoted preg_quote("\"$key\"", '/'), // Double quoted - preg_quote('__("' . $key . '")', '/'), // PHP translation function + preg_quote('__("'.$key.'")', '/'), // PHP translation function preg_quote("__('$key')", '/'), // PHP translation function - preg_quote('$tpl->__("' . $key . '")', '/'), // Template translation - preg_quote('$tpl->__(\'' . $key . '\')', '/'), // Template translation + preg_quote('$tpl->__("'.$key.'")', '/'), // Template translation + preg_quote('$tpl->__(\''.$key.'\')', '/'), // Template translation ]; if ($this->option('debug')) { @@ -108,7 +110,7 @@ private function scanFileForTranslations($file): void } foreach ($patterns as $pattern) { - if (preg_match('/' . $pattern . '/', $content)) { + if (preg_match('/'.$pattern.'/', $content)) { if ($this->option('debug')) { $this->line(" - Found usage of key: {$key}"); } @@ -125,6 +127,7 @@ private function generateReport(): void if (empty($unusedTranslations)) { $this->info('No unused translations found.'); + return; } diff --git a/app/Core/Configuration/laravelConfig.php b/app/Core/Configuration/laravelConfig.php index 1ed0b5a00b..9b5d1ad2e6 100644 --- a/app/Core/Configuration/laravelConfig.php +++ b/app/Core/Configuration/laravelConfig.php @@ -40,7 +40,7 @@ \Illuminate\Validation\ValidationServiceProvider::class, //\Illuminate\View\ViewServiceProvider::class, - \Leantime\Core\Providers\Auth::class, + \Leantime\Core\Providers\Authentication::class, \Leantime\Core\Providers\RateLimiter::class, \Leantime\Core\Providers\Db::class, \Leantime\Core\Providers\Language::class, @@ -94,7 +94,8 @@ 'channels' => [ 'stack' => [ 'driver' => 'stack', - 'channels' => ['single'], + // Add the Sentry log channel to the stack + 'channels' => ['single', 'sentry'], ], 'single' => [ 'driver' => 'daily', @@ -114,6 +115,11 @@ 'level' => 'critical', 'replace_placeholders' => true, ], + 'sentry' => [ + 'driver' => 'sentry', + 'level' => 'error', + 'bubble' => true, + ], ], 'default' => 'stack', ], @@ -129,6 +135,7 @@ | specified when running a cache operation inside the application. | */ + 'default' => 'installation', /* @@ -205,7 +212,7 @@ | */ - 'lifetime' => 480, //8 hours + 'lifetime' => env('LEAN_SESSION_EXPIRATION', 480), //8 hours 'expire_on_close' => false, @@ -389,6 +396,7 @@ 'compiled' => realpath(storage_path('framework/views')), ], + 'database' => [ 'default' => env('LEAN_DB_DEFAULT_CONNECTION', 'mysql'), /* @@ -439,7 +447,6 @@ ], ], - /* |-------------------------------------------------------------------------- | Redis Databases @@ -453,9 +460,11 @@ 'redis' => [ 'client' => 'phpredis', 'options' => [ + 'parameters' => ['timeout' => 1.0], 'cluster' => 'redis', 'context' => [], 'compression' => 3, // Redis::COMPRESSION_LZ4 + 'password' => '', ], 'default' => [ 'url' => env('LEAN_REDIS_URL', ''), @@ -464,7 +473,31 @@ 'password' => env('LEAN_REDIS_PASSWORD', null), 'port' => env('LEAN_REDIS_PORT', '127.0.0.1'), 'database' => '0', + 'read_timeout' => 1.0, + 'prefix' => 'leantime_cache', ], ], + // Driver options: eloquent, database (using db query builder), + 'auth' => [ + 'defaults' => [ + 'guard' => 'leantime', + 'passwords' => 'users', + ], + 'guards' => [ + 'leantime' => [ + 'driver' => 'leantime', + 'provider' => 'leantimeUsers', + ], + 'jsonRpc' => [ + 'driver' => 'jsonRpc', + 'provider' => 'leantimeUsers', + ], + ], + 'providers' => [ + 'leantimeUsers' => [ + 'driver' => 'leantimeUsers', + ], + ], + ], ]; diff --git a/app/Core/Contracts/Service.php b/app/Core/Contracts/Service.php deleted file mode 100644 index be81fad39e..0000000000 --- a/app/Core/Contracts/Service.php +++ /dev/null @@ -1,58 +0,0 @@ -value array where key represents the object field name and value the value. - * @return bool returns true on success, false on failure - */ - public function patch(int $id, array $params): bool; - - /** - * updates the object by key. - * - * @param object|array $object expects the entire object to be updated as object or array - * @return array|bool Returns true on success, false on failure - */ - public function update(object|array $object): array|bool; - - /** - * Creates a new object - * - * @param object|array $object Object or array to be created - * @return int|false Returns id of new element or false - */ - public function create(object|array $object): int|false; - - /** - * Deletes object - * - * @param int $id Id of the object to be deleted - * @return bool Returns id of new element or false - */ - public function delete(int $id); - - /** - * Gets 1 specific item - * - * @param int $id Id of the object to be retrieved - * @return object|array|false Returns object or array. False on failure or if item cannot be found - */ - public function get(int $id); - - /** - * Get all items - * - * @param array|null $searchparams Search parameters - * @return array|false Returns array on success, false on failure. No results should return empty array - */ - public function query(?array $searchparams = null); -} diff --git a/app/Core/Http/HttpKernel.php b/app/Core/Http/HttpKernel.php index 2415b2ab68..323c57c5fa 100644 --- a/app/Core/Http/HttpKernel.php +++ b/app/Core/Http/HttpKernel.php @@ -36,6 +36,8 @@ class HttpKernel extends Kernel \Leantime\Core\Middleware\StartSession::class, \Leantime\Core\Middleware\Installed::class, \Leantime\Core\Middleware\Updated::class, + \Leantime\Core\Middleware\AuthCheck::class, + \Leantime\Core\Middleware\RequestRateLimiter::class, \Illuminate\Http\Middleware\HandleCors::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, @@ -53,14 +55,14 @@ class HttpKernel extends Kernel */ protected $middlewareGroups = [ 'web' => [ - \Leantime\Core\Middleware\Auth::class, + \Leantime\Core\Middleware\CurrentProject::class, ], 'api' => [ - \Leantime\Core\Middleware\ApiAuth::class, + \Leantime\Core\Middleware\AuthCheck::class, ], 'hx' => [ - \Leantime\Core\Middleware\Auth::class, + \Leantime\Core\Middleware\AuthCheck::class, \Leantime\Core\Middleware\CurrentProject::class, ], ]; @@ -73,7 +75,7 @@ class HttpKernel extends Kernel * @var array */ protected $middlewareAliases = [ - //'auth' => \App\Http\Middleware\Authenticate::class, + 'auth' => \Leantime\Core\Middleware\AuthCheck::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, @@ -100,10 +102,10 @@ protected function sendRequestThroughRouter($request) if ($request instanceof ApiRequest) { - array_splice($this->middleware, 5, 0, $this->middlewareGroups['api']); + array_splice($this->middleware, 6, 0, $this->middlewareGroups['api']); } else { - array_splice($this->middleware, 5, 0, $this->middlewareGroups['web']); + array_splice($this->middleware, 6, 0, $this->middlewareGroups['web']); } //This filter only works for system plugins diff --git a/app/Core/Middleware/ApiAuth.php b/app/Core/Middleware/ApiAuth.php deleted file mode 100644 index 1536ddbe6a..0000000000 --- a/app/Core/Middleware/ApiAuth.php +++ /dev/null @@ -1,52 +0,0 @@ - app()]); - - $apiKey = $request->getAPIKey(); - $apiUser = false; - - if ($apiKey !== null) { - $apiUser = app()->make(ApiService::class)->getAPIKeyUser($apiKey); - } - - if (! $apiUser) { - return new Response(json_encode(['error' => 'Invalid API Key']), 401); - } - - app()->make(AuthService::class)->setUserSession($apiUser); - app()->make(ProjectsService::class)->setCurrentProject(); - - if (! str_starts_with(strtolower(app()->make(Frontcontroller::class)->getCurrentRoute()), 'api.jsonrpc')) { - return new Response(json_encode(['error' => 'Invalid API endpoint']), 404); - } - - return $next($request); - } -} diff --git a/app/Core/Middleware/Auth.php b/app/Core/Middleware/AuthCheck.php similarity index 73% rename from app/Core/Middleware/Auth.php rename to app/Core/Middleware/AuthCheck.php index 537d4f5313..1062e2a6c6 100644 --- a/app/Core/Middleware/Auth.php +++ b/app/Core/Middleware/AuthCheck.php @@ -4,16 +4,18 @@ use Closure; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cookie; use Illuminate\Support\Facades\Date; use Illuminate\Support\Str; +use Leantime\Core\Configuration\Environment; use Leantime\Core\Events\DispatchesEvents; +use Leantime\Core\Http\ApiRequest; use Leantime\Core\Http\IncomingRequest; -use Leantime\Domain\Auth\Services\Auth as AuthService; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; -class Auth +class AuthCheck { use DispatchesEvents; @@ -38,13 +40,14 @@ class Auth ]; public function __construct( - private AuthService $authService, + protected Environment $config ) { $this->publicActions = self::dispatchFilter('publicActions', $this->publicActions, ['bootloader' => $this]); } /** * Redirect with origin + * Returns false if the current route is already the redirection route. * * @return Response|RedirectResponse * @@ -75,10 +78,15 @@ public function handle(IncomingRequest $request, Closure $next): Response return $next($request); } - if (! $this->authService->loggedIn()) { - $loginRedirect = self::dispatch_filter('loginRoute', 'auth.login', ['request' => $request]); + $loginRedirect = self::dispatch_filter('loginRoute', 'auth.login', ['request' => $request]); - return $this->redirectWithOrigin($loginRedirect, $request->getRequestUri(), $request) ?: $next($request); + if ($request instanceof ApiRequest) { + self::dispatchEvent('before_api_request', ['application' => app()], 'leantime.core.middleware.apiAuth.handle'); + } + $authCheckResponse = $this->authenticate($request, array_keys($this->config->get('auth.guards')), $loginRedirect, $next); + + if ($authCheckResponse !== true) { + return $authCheckResponse; } // Check if trying to access twoFA code page, or if trying to access any other action without verifying the code. @@ -90,7 +98,7 @@ public function handle(IncomingRequest $request, Closure $next): Response $response = $next($request); - if ($this->authService->loggedIn()) { + if ($authCheckResponse === true) { //Set cookie to increase session timeout $response->headers->setCookie(new \Symfony\Component\HttpFoundation\Cookie( @@ -112,6 +120,28 @@ public function handle(IncomingRequest $request, Closure $next): Response return $response; } + protected function authenticate($request, array $guards, $loginRedirect, $next) + { + if (empty($guards)) { + $guards = [null]; + } + + foreach ($guards as $guard) { + if (Auth::guard($guard)->check()) { + Auth::shouldUse($guard); + + return true; + } + } + + if ($request instanceof APIRequest) { + return new Response(json_encode(['error' => 'Invalid API Key']), 401); + } + + return $this->redirectWithOrigin($loginRedirect, $request->getRequestUri(), $request) ?: $next($request); + + } + public function isPublicController($currentPath) { diff --git a/app/Core/Plugins/PluginManager.php b/app/Core/Plugins/PluginManager.php new file mode 100644 index 0000000000..bbad1a1d61 --- /dev/null +++ b/app/Core/Plugins/PluginManager.php @@ -0,0 +1,16 @@ +app->singleton(AuthService::class, AuthService::class); - $this->app->singleton(OidcService::class, OidcService::class); - - } -} diff --git a/app/Core/Providers/Authentication.php b/app/Core/Providers/Authentication.php new file mode 100644 index 0000000000..e0ce5cf4c1 --- /dev/null +++ b/app/Core/Providers/Authentication.php @@ -0,0 +1,52 @@ +app->singleton(AuthService::class, AuthService::class); + //$this->app->singleton(OidcService::class, OidcService::class); + $this->app->singleton('auth', function ($app) { + return new \Illuminate\Auth\AuthManager($app); + }); + } + + public function boot() + { + + $this->app['auth']->provider('leantimeUsers', function ($app, array $config) { + return new LeantimeUserProvider( + $app->make(\Leantime\Domain\Auth\Services\Auth::class) + ); + }); + + $this->app['auth']->extend('leantime', function ($app, $name, array $config) { + return new LeantimeGuard( + $app['auth']->createUserProvider($config['provider']), + $app->make(\Leantime\Domain\Auth\Services\Auth::class) + ); + }); + + $this->app['auth']->extend('jsonRpc', function ($app, $name, array $config) { + return new ApiGuard( + $app['auth']->createUserProvider($config['provider']), + $app->make(\Leantime\Domain\Api\Services\Api::class), + $app['request'] + ); + }); + } +} diff --git a/app/Core/Providers/Redis.php b/app/Core/Providers/Redis.php index 311eaa14fe..a871dd57d6 100644 --- a/app/Core/Providers/Redis.php +++ b/app/Core/Providers/Redis.php @@ -14,16 +14,15 @@ class Redis extends ServiceProvider */ public function register() { + // Ensure cluster configuration is properly set before we configure stores + if ($this->app['config']->useCluster) { + $this->app['config']->set('redis.client', 'phpredis'); + $this->app['config']->set('redis.cluster', 'redis'); + } - /** - * @todo the following should eventually automatically turn caches into redis if available, - * then memcached if available, - * then fileStore - */ $this->app->singleton('redis', function ($app) { - //Setting up three different redis stores - //We are using a slightlyt diffewrent config structure and keep redis at the root level of our config + //We are using a slightly different config structure and keep redis at the root level of our config $cacheConfig = $app['config']['redis']['default']; $cacheConfig['prefix'] = 'leantime_cache:'; @@ -37,8 +36,8 @@ public function register() //Prepare available redis connections //These connections (cache, installation, sessions) can be used for sessions and cache if ($app['config']->useCluster) { - //Cluster configs and prefix management works differently than regular connections + $app['config']->set('redis.clusters.default', [$app['config']['redis']['default']]); $options = $app['config']['redis']['options']; //The default config is not needed anymore and shouldn't be used since the connection is a cluster @@ -55,18 +54,20 @@ public function register() $app['config']->set('redis.clusters.sessions', array_merge(['options' => $options], [$sessionsConfig])); $app['config']->set('redis.clusters.sessions.options.prefix', $sessionsConfig['prefix']); + // Set cluster specific options + $app['config']->set('redis.options', [ + 'cluster' => 'redis', + 'parameters' => ['timeout' => 1.0], + ]); } else { - $app['config']->set('redis.cache', $cacheConfig); $app['config']->set('redis.installation', $installationConfig); $app['config']->set('redis.sessions', $sessionsConfig); - } $redisManager = new RedisManager($app, 'phpredis', $app['config']['redis']); return $redisManager; - }); $this->app->bind('redis.connection', function ($app) { diff --git a/app/Domain/Auth/Guards/ApiGuard.php b/app/Domain/Auth/Guards/ApiGuard.php new file mode 100644 index 0000000000..8dbd53320c --- /dev/null +++ b/app/Domain/Auth/Guards/ApiGuard.php @@ -0,0 +1,91 @@ +apiKey = $this->request->getAPIKey(); + } + + public function check() + { + $apiUser = $this->apiService->getAPIKeyUser($this->apiKey); + + if (! $apiUser) { + return false; + } + + return true; + } + + public function guest() + { + return ! $this->check(); + } + + public function user() + { + if ($this->user !== null) { + return $this->user; + } + + $apiUser = $this->apiService->getAPIKeyUser($this->apiKey); + + if (! $apiUser) { + $this->user = null; + + return $this->user; + } + + $this->user = (object) $apiUser; + + return $this->user; + } + + public function id() + { + if ($this->user()) { + return $this->user()->id; + } + } + + public function validate(array $credentials = []) + { + + $apiUser = $this->apiService->getAPIKeyUser($this->apiKey); + + if (! $apiUser) { + return false; + } + + return true; + + } + + public function hasUser() + { + return $this->user ? true : false; + } + + public function setUser(Authenticatable $user) + { + $this->user = $user; + + return $this; + } +} diff --git a/app/Domain/Auth/Guards/LeantimeGuard.php b/app/Domain/Auth/Guards/LeantimeGuard.php new file mode 100644 index 0000000000..4f5e5a502c --- /dev/null +++ b/app/Domain/Auth/Guards/LeantimeGuard.php @@ -0,0 +1,73 @@ +provider = $provider; + $this->authService = $authService; + } + + public function check() + { + return $this->authService->loggedIn(); + } + + public function guest() + { + return ! $this->check(); + } + + public function user() + { + if ($this->user !== null) { + return $this->user; + } + + if ($this->authService->loggedIn()) { + $this->user = $this->provider->retrieveById($this->authService::getUserId()); + } + + return $this->user; + } + + public function hasUser() + { + return $this->user ? true : false; + } + + public function id() + { + if ($this->user()) { + return $this->user()->id; + } + } + + public function validate(array $credentials = []) + { + return $this->authService->login( + $credentials['username'], + $credentials['password'] + ); + } + + public function setUser(Authenticatable $user) + { + $this->user = $user; + + return $this; + } +} diff --git a/app/Domain/Auth/Providers/LeantimeUserProvider.php b/app/Domain/Auth/Providers/LeantimeUserProvider.php new file mode 100644 index 0000000000..7af5e67a8b --- /dev/null +++ b/app/Domain/Auth/Providers/LeantimeUserProvider.php @@ -0,0 +1,54 @@ +authService = $authService; + } + + public function retrieveById($identifier) + { + return $this->authService->getUserById($identifier); + } + + public function retrieveByToken($identifier, $token) + { + return null; // Not implemented for now + } + + public function updateRememberToken(Authenticatable $user, $token) + { + // Not implemented for now + } + + public function retrieveByCredentials(array $credentials) + { + if (! isset($credentials['username'])) { + return null; + } + + return $this->authService->getUserByLogin( + $credentials['username'], + $credentials['password'] ?? null + ); + } + + public function validateCredentials(Authenticatable $user, array $credentials) + { + return $this->authService->login( + $credentials['username'], + $credentials['password'] + ); + } + + public function rehashPasswordIfRequired() {} +} diff --git a/app/Domain/Auth/Services/Auth.php b/app/Domain/Auth/Services/Auth.php index f842647607..d9557c92f0 100644 --- a/app/Domain/Auth/Services/Auth.php +++ b/app/Domain/Auth/Services/Auth.php @@ -2,6 +2,7 @@ namespace Leantime\Domain\Auth\Services; +use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Session\SessionManager; @@ -19,9 +20,9 @@ use Leantime\Domain\Users\Repositories\Users as UserRepository; use RobThree\Auth\TwoFactorAuth; -class Auth +class Auth implements Authenticatable { - use DispatchesEvents; + use DispatchesEvents, \Illuminate\Auth\Authenticatable; /** * @var int|null user id from DB @@ -276,7 +277,7 @@ public function login(string $username, string $password): bool * * @throws BindingResolutionException */ - public function setUsersession(mixed $user, bool $isLdap = false) + public function setUserSession(mixed $user, bool $isLdap = false) { if (! $user || ! is_array($user)) { return false; @@ -363,7 +364,7 @@ public function logout(): void 'projectsettings', 'currentSubscriptions', 'lastTicketView', - 'lastFilterdTicketTableView', + 'lastFilteredTicketTableView', ]); foreach ($sessionsToDestroy as $key) { @@ -520,9 +521,9 @@ public function use2FA(): mixed public function verify2FA(string $code): bool { - $tfa = new TwoFactorAuth('Leantime'); + $twoFactorAuthentication = new TwoFactorAuth('Leantime'); - return $tfa->verifyCode(session('userdata.twoFASecret'), $code); + return $twoFactorAuthentication->verifyCode(session('userdata.twoFASecret'), $code); } public function get2FAVerified(): mixed @@ -546,4 +547,44 @@ private function logFailedLogin(string $user): void Log::info($msg); } + + public function getAuthIdentifierName() + { + return 'id'; + } + + public function getAuthIdentifier() + { + return $this->userId; + } + + public function getAuthPassword() + { + return $this->password; + } + + public function getAuthPasswordName() + { + return 'password'; + } + + public function getRememberToken() + { + return null; // Not implemented yet + } + + public function setRememberToken($value) + { + // Not implemented yet + } + + public function getRememberTokenName() + { + return 'remember_token'; + } + + public function getUserById($id) + { + return (object) $this->userRepo->getUser($id); + } } diff --git a/app/Plugins b/app/Plugins index 6d91f5b0e7..0efdb2a73e 160000 --- a/app/Plugins +++ b/app/Plugins @@ -1 +1 @@ -Subproject commit 6d91f5b0e722c81a342d327cfd20c3f1c0df108a +Subproject commit 0efdb2a73efbaa7700c5e09f9aee5ab880e557a7 diff --git a/composer.json b/composer.json index 7c60e6adbb..ecc6916399 100644 --- a/composer.json +++ b/composer.json @@ -80,14 +80,13 @@ "symfony/var-dumper": "^6.2", "nikic/php-parser": "^4.17", "nesbot/carbon": "^2.72", - "predis/predis": "^2.2", - "sentry/sentry-laravel": "^4.8", "symfony/http-client": "^6.2.4", "symfony/psr-http-message-bridge": "^2.0", "carbon-cli/carbon-cli": "^1.2", "metasyntactical/composer-plugin-license-check": "^2.1", "phpseclib/phpseclib": "~3.0", - "spatie/icalendar-generator": "^2.6" + "spatie/icalendar-generator": "^2.6", + "sentry/sentry-laravel": "4.10.1" }, "require-dev": { "squizlabs/php_codesniffer": "^3.8", diff --git a/composer.lock b/composer.lock index 7f6621348a..6e58218a1d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ed18989f7a7a3d4862538faeb25fd366", + "content-hash": "6da8ff51b0c68294755ec8195ccd5b99", "packages": [ { "name": "aws/aws-crt-php", @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.328.0", + "version": "3.330.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "a99b58e166ae367f2b067937afb04e843e900745" + "reference": "136749f15d1dbff07064ef5ba1c2f08b96cf78ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a99b58e166ae367f2b067937afb04e843e900745", - "reference": "a99b58e166ae367f2b067937afb04e843e900745", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/136749f15d1dbff07064ef5ba1c2f08b96cf78ff", + "reference": "136749f15d1dbff07064ef5ba1c2f08b96cf78ff", "shasum": "" }, "require": { @@ -101,7 +101,7 @@ "paragonie/random_compat": ">= 2", "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", "psr/cache": "^1.0", - "psr/simple-cache": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", "sebastian/comparator": "^1.2.3 || ^4.0", "yoast/phpunit-polyfills": "^1.0" }, @@ -154,9 +154,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.328.0" + "source": "https://github.com/aws/aws-sdk-php/tree/3.330.1" }, - "time": "2024-11-15T19:06:57+00:00" + "time": "2024-11-25T19:20:00+00:00" }, { "name": "bacon/bacon-qr-code", @@ -1711,28 +1711,28 @@ }, { "name": "jean85/pretty-package-versions", - "version": "2.0.6", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4" + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", "shasum": "" }, "require": { - "composer-runtime-api": "^2.0.0", - "php": "^7.1|^8.0" + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", "jean85/composer-provided-replaced-stub-package": "^1.0", "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^7.5|^8.5|^9.4", - "vimeo/psalm": "^4.3" + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "vimeo/psalm": "^4.3 || ^5.0" }, "type": "library", "extra": { @@ -1764,9 +1764,9 @@ ], "support": { "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6" + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" }, - "time": "2024-03-08T09:58:59+00:00" + "time": "2024-11-18T16:19:46+00:00" }, { "name": "kamermans/guzzle-oauth2-subscriber", @@ -1874,16 +1874,16 @@ }, { "name": "laravel/framework", - "version": "v10.48.23", + "version": "v10.48.24", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "625269ca4881d2b50eded2045cb930960a181d98" + "reference": "2add73f71b88fc45ee1d4f3421f22366247f6155" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/625269ca4881d2b50eded2045cb930960a181d98", - "reference": "625269ca4881d2b50eded2045cb930960a181d98", + "url": "https://api.github.com/repos/laravel/framework/zipball/2add73f71b88fc45ee1d4f3421f22366247f6155", + "reference": "2add73f71b88fc45ee1d4f3421f22366247f6155", "shasum": "" }, "require": { @@ -2077,7 +2077,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-11-12T15:39:10+00:00" + "time": "2024-11-20T15:57:07+00:00" }, { "name": "laravel/prompts", @@ -2139,16 +2139,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.6", + "version": "v1.3.7", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f865a58ea3a0107c336b7045104c75243fa59d96" + "reference": "4f48ade902b94323ca3be7646db16209ec76be3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f865a58ea3a0107c336b7045104c75243fa59d96", - "reference": "f865a58ea3a0107c336b7045104c75243fa59d96", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/4f48ade902b94323ca3be7646db16209ec76be3d", + "reference": "4f48ade902b94323ca3be7646db16209ec76be3d", "shasum": "" }, "require": { @@ -2196,7 +2196,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-11-11T17:06:04+00:00" + "time": "2024-11-14T18:34:49+00:00" }, { "name": "lasserafn/php-initial-avatar-generator", @@ -3555,32 +3555,32 @@ }, { "name": "nunomaduro/termwind", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "dcf1ec3dfa36137b7ce41d43866644a7ab8fc257" + "reference": "5369ef84d8142c1d87e4ec278711d4ece3cbf301" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dcf1ec3dfa36137b7ce41d43866644a7ab8fc257", - "reference": "dcf1ec3dfa36137b7ce41d43866644a7ab8fc257", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/5369ef84d8142c1d87e4ec278711d4ece3cbf301", + "reference": "5369ef84d8142c1d87e4ec278711d4ece3cbf301", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.1", - "symfony/console": "^6.4.12" + "symfony/console": "^6.4.15" }, "require-dev": { - "illuminate/console": "^10.48.22", - "illuminate/support": "^10.48.22", - "laravel/pint": "^1.18.1", - "pestphp/pest": "^2", + "illuminate/console": "^10.48.24", + "illuminate/support": "^10.48.24", + "laravel/pint": "^1.18.2", + "pestphp/pest": "^2.36.0", "pestphp/pest-plugin-mock": "2.0.0", - "phpstan/phpstan": "^1.12.6", + "phpstan/phpstan": "^1.12.11", "phpstan/phpstan-strict-rules": "^1.6.1", - "symfony/var-dumper": "^6.4.11", + "symfony/var-dumper": "^6.4.15", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -3620,7 +3620,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v1.16.0" + "source": "https://github.com/nunomaduro/termwind/tree/v1.17.0" }, "funding": [ { @@ -3636,7 +3636,7 @@ "type": "github" } ], - "time": "2024-10-15T15:27:12+00:00" + "time": "2024-11-21T10:36:35+00:00" }, { "name": "nyholm/psr7", @@ -3908,16 +3908,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.2", + "version": "v6.9.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c" + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a7b17b42fa4887c92146243f3d2f4ccb962af17c", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", "shasum": "" }, "require": { @@ -3977,7 +3977,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.2" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" }, "funding": [ { @@ -3985,7 +3985,7 @@ "type": "github" } ], - "time": "2024-10-09T10:07:50+00:00" + "time": "2024-11-24T18:04:13+00:00" }, { "name": "phpoption/phpoption", @@ -4172,67 +4172,6 @@ ], "time": "2024-09-16T03:06:04+00:00" }, - { - "name": "predis/predis", - "version": "v2.2.2", - "source": { - "type": "git", - "url": "https://github.com/predis/predis.git", - "reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/predis/predis/zipball/b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1", - "reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.3", - "phpstan/phpstan": "^1.9", - "phpunit/phpunit": "^8.0 || ~9.4.4" - }, - "suggest": { - "ext-relay": "Faster connection with in-memory caching (>=0.6.2)" - }, - "type": "library", - "autoload": { - "psr-4": { - "Predis\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Till Krüss", - "homepage": "https://till.im", - "role": "Maintainer" - } - ], - "description": "A flexible and feature-complete Redis client for PHP.", - "homepage": "http://github.com/predis/predis", - "keywords": [ - "nosql", - "predis", - "redis" - ], - "support": { - "issues": "https://github.com/predis/predis/issues", - "source": "https://github.com/predis/predis/tree/v2.2.2" - }, - "funding": [ - { - "url": "https://github.com/sponsors/tillkruss", - "type": "github" - } - ], - "time": "2023-09-13T16:42:03+00:00" - }, { "name": "psr/cache", "version": "3.0.0", @@ -5080,16 +5019,16 @@ }, { "name": "sentry/sentry-laravel", - "version": "4.10.0", + "version": "4.10.1", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-laravel.git", - "reference": "cbdd224cc5a224528bf6b19507ad76187b3bccfa" + "reference": "1c007fb111ff00f02efba2aca022310dae412c3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/cbdd224cc5a224528bf6b19507ad76187b3bccfa", - "reference": "cbdd224cc5a224528bf6b19507ad76187b3bccfa", + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/1c007fb111ff00f02efba2aca022310dae412c3a", + "reference": "1c007fb111ff00f02efba2aca022310dae412c3a", "shasum": "" }, "require": { @@ -5153,7 +5092,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-laravel/issues", - "source": "https://github.com/getsentry/sentry-laravel/tree/4.10.0" + "source": "https://github.com/getsentry/sentry-laravel/tree/4.10.1" }, "funding": [ { @@ -5165,7 +5104,7 @@ "type": "custom" } ], - "time": "2024-11-07T08:05:24+00:00" + "time": "2024-11-24T11:02:20+00:00" }, { "name": "simple-cli/simple-cli", @@ -5227,16 +5166,16 @@ }, { "name": "simplepie/simplepie", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/simplepie/simplepie.git", - "reference": "65b095d87bc00898d8fa7737bdbcda93a3fbcc55" + "reference": "a567b8ab9b6145a23e6a9ec2b6b74f56d52f7ad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplepie/simplepie/zipball/65b095d87bc00898d8fa7737bdbcda93a3fbcc55", - "reference": "65b095d87bc00898d8fa7737bdbcda93a3fbcc55", + "url": "https://api.github.com/repos/simplepie/simplepie/zipball/a567b8ab9b6145a23e6a9ec2b6b74f56d52f7ad1", + "reference": "a567b8ab9b6145a23e6a9ec2b6b74f56d52f7ad1", "shasum": "" }, "require": { @@ -5297,9 +5236,9 @@ ], "support": { "issues": "https://github.com/simplepie/simplepie/issues", - "source": "https://github.com/simplepie/simplepie/tree/1.8.0" + "source": "https://github.com/simplepie/simplepie/tree/1.8.1" }, - "time": "2023-01-20T08:37:35+00:00" + "time": "2024-11-22T16:33:20+00:00" }, { "name": "spatie/enum", @@ -8687,16 +8626,16 @@ }, { "name": "voku/portable-ascii", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "b56450eed252f6801410d810c8e1727224ae0743" + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", - "reference": "b56450eed252f6801410d810c8e1727224ae0743", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", "shasum": "" }, "require": { @@ -8721,7 +8660,7 @@ "authors": [ { "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "homepage": "https://www.moelleken.org/" } ], "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", @@ -8733,7 +8672,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.1" + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" }, "funding": [ { @@ -8757,7 +8696,7 @@ "type": "tidelift" } ], - "time": "2022-03-08T17:03:00+00:00" + "time": "2024-11-21T01:49:47+00:00" }, { "name": "webmozart/assert", @@ -9877,16 +9816,16 @@ }, { "name": "laravel/pint", - "version": "v1.18.1", + "version": "v1.18.2", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9" + "reference": "f55daaf7eb6c2f49ddf6702fb42e3091c64d8a64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/35c00c05ec43e6b46d295efc0f4386ceb30d50d9", - "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9", + "url": "https://api.github.com/repos/laravel/pint/zipball/f55daaf7eb6c2f49ddf6702fb42e3091c64d8a64", + "reference": "f55daaf7eb6c2f49ddf6702fb42e3091c64d8a64", "shasum": "" }, "require": { @@ -9939,7 +9878,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-09-24T17:22:50+00:00" + "time": "2024-11-20T09:33:46+00:00" }, { "name": "leantime/leantime-documentor", @@ -10270,16 +10209,16 @@ }, { "name": "php-webdriver/webdriver", - "version": "1.15.1", + "version": "1.15.2", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", - "reference": "cd52d9342c5aa738c2e75a67e47a1b6df97154e8" + "reference": "998e499b786805568deaf8cbf06f4044f05d91bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/cd52d9342c5aa738c2e75a67e47a1b6df97154e8", - "reference": "cd52d9342c5aa738c2e75a67e47a1b6df97154e8", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/998e499b786805568deaf8cbf06f4044f05d91bf", + "reference": "998e499b786805568deaf8cbf06f4044f05d91bf", "shasum": "" }, "require": { @@ -10301,7 +10240,7 @@ "php-parallel-lint/php-parallel-lint": "^1.2", "phpunit/phpunit": "^9.3", "squizlabs/php_codesniffer": "^3.5", - "symfony/var-dumper": "^5.0 || ^6.0" + "symfony/var-dumper": "^5.0 || ^6.0 || ^7.0" }, "suggest": { "ext-SimpleXML": "For Firefox profile creation" @@ -10330,9 +10269,9 @@ ], "support": { "issues": "https://github.com/php-webdriver/php-webdriver/issues", - "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.1" + "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.2" }, - "time": "2023-10-20T12:21:20+00:00" + "time": "2024-11-21T15:12:59+00:00" }, { "name": "phpcsstandards/phpcsextra", @@ -10502,21 +10441,21 @@ }, { "name": "phpdocumentor/reflection", - "version": "6.0.0", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/Reflection.git", - "reference": "61e2f1fe7683e9647b9ed8d9e53d08699385267d" + "reference": "bb4dea805a645553d6d989b23dad9f8041f39502" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/61e2f1fe7683e9647b9ed8d9e53d08699385267d", - "reference": "61e2f1fe7683e9647b9ed8d9e53d08699385267d", + "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/bb4dea805a645553d6d989b23dad9f8041f39502", + "reference": "bb4dea805a645553d6d989b23dad9f8041f39502", "shasum": "" }, "require": { "nikic/php-parser": "~4.18 || ^5.0", - "php": "8.1.*|8.2.*|8.3.*", + "php": "8.1.*|8.2.*|8.3.*|8.4.*", "phpdocumentor/reflection-common": "^2.1", "phpdocumentor/reflection-docblock": "^5", "phpdocumentor/type-resolver": "^1.2", @@ -10563,9 +10502,9 @@ ], "support": { "issues": "https://github.com/phpDocumentor/Reflection/issues", - "source": "https://github.com/phpDocumentor/Reflection/tree/6.0.0" + "source": "https://github.com/phpDocumentor/Reflection/tree/6.1.0" }, - "time": "2024-05-23T19:28:12+00:00" + "time": "2024-11-22T15:11:54+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -10791,16 +10730,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.10", + "version": "1.12.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" + "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", + "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", "shasum": "" }, "require": { @@ -10845,7 +10784,7 @@ "type": "github" } ], - "time": "2024-11-11T15:37:09+00:00" + "time": "2024-11-17T14:08:01+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/tests/Unit/app/Core/ApiClientTest.php b/tests/Unit/app/Core/ApiClientTest.php index 6dae43cd4a..445bd9830f 100644 --- a/tests/Unit/app/Core/ApiClientTest.php +++ b/tests/Unit/app/Core/ApiClientTest.php @@ -7,7 +7,7 @@ class ApiClientTest extends \Unit\TestCase { - public function testOAuth2(): void + public function test_o_auth2(): void { $baseUri = 'http://test.com'; $stack = HandlerStack::create(); @@ -20,7 +20,7 @@ public function testOAuth2(): void $this->assertEquals('oauth', $client->getConfig('auth')); } - public function testOAuth2Grants(): void + public function test_o_auth2_grants(): void { $baseUri = 'http://test.com'; $creds = [ @@ -33,7 +33,7 @@ public function testOAuth2Grants(): void $this->assertInstanceOf(HandlerStack::class, $stack); } - public function testOAuth1(): void + public function test_o_auth1(): void { $baseUri = 'http://test.com'; $creds = [ @@ -49,7 +49,7 @@ public function testOAuth1(): void $this->assertEquals('oauth', $client->getConfig('auth')); } - public function testBasicAuth(): void + public function test_basic_auth(): void { $baseUri = 'http://test.com'; $creds = [ @@ -63,7 +63,7 @@ public function testBasicAuth(): void $this->assertEquals($creds, $client->getConfig('auth')); } - public function testDigest(): void + public function test_digest(): void { $baseUri = 'http://test.com'; $creds = [ @@ -79,7 +79,7 @@ public function testDigest(): void $this->assertEquals($creds, $config[1]['auth']); } - public function testNtlm(): void + public function test_ntlm(): void { $baseUri = 'http://test.com'; $creds = [ diff --git a/tests/Unit/app/Core/ApplicationUrlTest.php b/tests/Unit/app/Core/ApplicationUrlTest.php index 7b46da66c9..c5c354db5e 100644 --- a/tests/Unit/app/Core/ApplicationUrlTest.php +++ b/tests/Unit/app/Core/ApplicationUrlTest.php @@ -33,7 +33,7 @@ protected function bootstrapApplication() $this->config = $this->app['config']; } - public function testBaseUrlIsSetCorrectlyFromConfig(): void + public function test_base_url_is_set_correctly_from_config(): void { // Test default behavior (no LEAN_APP_URL set) $this->assertEquals('http://localhost', BASE_URL); @@ -52,7 +52,7 @@ public function testBaseUrlIsSetCorrectlyFromConfig(): void $this->assertEquals('https://example.com', $this->config->get('appUrl')); } - public function testBaseUrlHandlesTrailingSlash(): void + public function test_base_url_handles_trailing_slash(): void { $_ENV['LEAN_APP_URL'] = 'https://example.com/'; @@ -63,7 +63,7 @@ public function testBaseUrlHandlesTrailingSlash(): void $this->assertEquals('https://example.com', $this->config->get('appUrl')); } - public function testBaseUrlHandlesSubdirectory(): void + public function test_base_url_handles_subdirectory(): void { $_ENV['LEAN_APP_URL'] = 'https://example.com/leantime'; @@ -74,7 +74,7 @@ public function testBaseUrlHandlesSubdirectory(): void $this->assertEquals('https://example.com/leantime', $this->config->get('appUrl')); } - public function testBaseUrlHandlesPort(): void + public function test_base_url_handles_port(): void { $_ENV['LEAN_APP_URL'] = 'https://example.com:8443'; @@ -85,7 +85,7 @@ public function testBaseUrlHandlesPort(): void $this->assertEquals('https://example.com:8443', $this->config->get('appUrl')); } - public function testBaseUrlHandlesReverseProxy(): void + public function test_base_url_handles_reverse_proxy(): void { // Simulate reverse proxy headers $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https'; diff --git a/tests/Unit/app/Core/Events/EventsTest.php b/tests/Unit/app/Core/Events/EventsTest.php index 45e8fe237a..a5bf1aa691 100644 --- a/tests/Unit/app/Core/Events/EventsTest.php +++ b/tests/Unit/app/Core/Events/EventsTest.php @@ -11,7 +11,7 @@ class EventsTest extends Unit * This test will check the dispatch_event method of the EventDispatcher class. * It will dispatch an event and assert if it is added to the available_hooks array. */ - public function testDispatchEvent() + public function test_dispatch_event() { $eventName = 'test.event.name'; $payload = ['testKey' => 'testValue']; @@ -30,7 +30,7 @@ public function testDispatchEvent() /** * This test will check the findEventListeners method of the EventDispatcher class. */ - public function testFindEventListeners() + public function test_find_event_listeners() { $eventName = 'test.event.name'; $listenerName = 'test.listener'; @@ -48,7 +48,7 @@ public function testFindEventListeners() * It will add new event listener and a new filter listener and check both listeners * are in the registry arrays. */ - public function testGetRegistries() + public function test_get_registries() { $eventName = 'event.test.name'; $filterName = 'filter.test.name'; diff --git a/tests/Unit/app/Core/UI/ThemeTest.php b/tests/Unit/app/Core/UI/ThemeTest.php index 70aa891b81..da40276da1 100644 --- a/tests/Unit/app/Core/UI/ThemeTest.php +++ b/tests/Unit/app/Core/UI/ThemeTest.php @@ -65,7 +65,7 @@ protected function _after() /** * Test GetMenuTypes method */ - public function testGetDefaultColorSchemeWithColorEnvSet() + public function test_get_default_color_scheme_with_color_env_set() { //Load class to be tested @@ -84,7 +84,7 @@ public function testGetDefaultColorSchemeWithColorEnvSet() /** * Test GetMenuTypes method */ - public function testGetDefaultColorSchemeWithoutEnv() + public function test_get_default_color_scheme_without_env() { $configMock = $this->make(Environment::class, []); diff --git a/tests/Unit/app/Domain/Api/Controllers/JsonrpcTest.php b/tests/Unit/app/Domain/Api/Controllers/JsonrpcTest.php index 7ae5b2a3fb..755839bad6 100644 --- a/tests/Unit/app/Domain/Api/Controllers/JsonrpcTest.php +++ b/tests/Unit/app/Domain/Api/Controllers/JsonrpcTest.php @@ -32,7 +32,7 @@ protected function setUp(): void $_SERVER['REQUEST_METHOD'] = 'post'; } - public function testMethodStringParsing() + public function test_method_string_parsing() { $params = [ 'method' => 'leantime.rpc.Comments.pollComments', @@ -53,7 +53,7 @@ public function testMethodStringParsing() $this->controller->post($params); } - public function testInvalidMethodString() + public function test_invalid_method_string() { $params = [ 'method' => 'invalid.method.string', @@ -74,7 +74,7 @@ public function testInvalidMethodString() $this->controller->post($params); } - public function testMissingJsonRpcVersion() + public function test_missing_json_rpc_version() { $params = [ 'method' => 'leantime.rpc.Comments.pollComments', @@ -94,7 +94,7 @@ public function testMissingJsonRpcVersion() $this->controller->post($params); } - public function testBatchRequest() + public function test_batch_request() { $params = [ [ diff --git a/tests/Unit/app/Domain/Calendar/Services/CalendarServiceTest.php b/tests/Unit/app/Domain/Calendar/Services/CalendarServiceTest.php index fe17c16c89..9998565a81 100644 --- a/tests/Unit/app/Domain/Calendar/Services/CalendarServiceTest.php +++ b/tests/Unit/app/Domain/Calendar/Services/CalendarServiceTest.php @@ -69,7 +69,7 @@ protected function _after() /** * Test GetMenuTypes method */ - public function testGetICalUrl() + public function test_get_i_cal_url() { //Sha is generated from id -1 and sessionpassword 123abc diff --git a/tests/Unit/app/Domain/Menu/Repositories/MenuRepositoryTest.php b/tests/Unit/app/Domain/Menu/Repositories/MenuRepositoryTest.php index 3f681bb6a0..c4b845cff5 100644 --- a/tests/Unit/app/Domain/Menu/Repositories/MenuRepositoryTest.php +++ b/tests/Unit/app/Domain/Menu/Repositories/MenuRepositoryTest.php @@ -62,7 +62,7 @@ protected function _after() /** * Test GetMenuTypes method */ - public function testGetMenuTypes() + public function test_get_menu_types() { $result = $this->menu->getMenuTypes(); @@ -75,7 +75,7 @@ public function testGetMenuTypes() // Further assertions can be done depending on use case and requirements } - public function testGetDefaultMenuStructure() + public function test_get_default_menu_structure() { $expected = $this->menu::DEFAULT_MENU; $defaultStructure = $this->menu->getMenuStructure(); @@ -89,7 +89,7 @@ public function testGetDefaultMenuStructure() $this->assertEquals($this->menu->menuStructures[$expected], $defaultStructure, 'Default menu structure does not match the expected structure'); } - public function testGetFullMenuStructure() + public function test_get_full_menu_structure() { $expected = 'full_menu'; $fullMenuStructure = $this->menu->getMenuStructure('full_menu'); @@ -98,14 +98,14 @@ public function testGetFullMenuStructure() $this->assertEquals($this->menu->menuStructures[$expected], $fullMenuStructure, 'Full menu structure does not match the expected structure'); } - public function testGetInvalidMenuStructure() + public function test_get_invalid_menu_structure() { $expected = []; $invalidMenuStructure = $this->menu->getMenuStructure('invalid'); $this->assertEquals($expected, $invalidMenuStructure, 'Invalid menu structure does not match the expected structure'); } - public function testGetFilteredMenuStructure() + public function test_get_filtered_menu_structure() { \Leantime\Core\Events\EventDispatcher::add_filter_listener('leantime.domain.menu.repositories.menu.getMenuStructure.menuStructures.company', function ($menu) { @@ -125,7 +125,7 @@ public function testGetFilteredMenuStructure() } - public function testInjectNewProjectMenuType() + public function test_inject_new_project_menu_type() { \Leantime\Core\Events\EventDispatcher::add_filter_listener('leantime.domain.menu.repositories.menu.getMenuStructure.menuStructures', function ($menuStructure) { diff --git a/tests/Unit/app/FormatTest.php b/tests/Unit/app/FormatTest.php index a6d6606fec..a9f300e4a2 100644 --- a/tests/Unit/app/FormatTest.php +++ b/tests/Unit/app/FormatTest.php @@ -41,7 +41,7 @@ protected function setUp(): void } - public function testDate(): void + public function test_date(): void { $formattedDateString = '12/31/2021'; $dbDate = '2022-01-01 00:00:00'; @@ -50,7 +50,7 @@ public function testDate(): void $this->assertSame($formattedDateString, $format->date()); } - public function testTime(): void + public function test_time(): void { $formattedTimeString = '04:00 PM'; $dbDate = '2022-01-01 00:00:00'; @@ -59,7 +59,7 @@ public function testTime(): void $this->assertSame($formattedTimeString, $format->time()); } - public function testTime24(): void + public function test_time24(): void { $formattedTimeString = '16:00'; $dbDate = '2022-01-01 00:00:00';