From d44d67df50d0efea562f8b5e2f92f46b30dad45c Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 20 May 2024 15:40:28 +0800 Subject: [PATCH 1/8] hotfix two fa --- composer.json | 2 +- config/responsecache.php | 2 +- src/Mail/VerificationMail.php | 1 + src/Support/TwoFactorAuth.php | 13 +++++++++---- src/routes.php | 2 +- views/mail/verification.blade.php | 8 +++++--- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 834c334..950c5d8 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "fleetbase/core-api", - "version": "1.4.24", + "version": "1.4.25", "description": "Core Framework and Resources for Fleetbase API", "keywords": [ "fleetbase", diff --git a/config/responsecache.php b/config/responsecache.php index 1771101..f46be37 100644 --- a/config/responsecache.php +++ b/config/responsecache.php @@ -79,7 +79,7 @@ * * You may use a string or an array here. */ - 'cache_tag' => '', + 'cache_tag' => 'fleetbase-responsecache', /* * This class is responsible for generating a hash for a request. This hash diff --git a/src/Mail/VerificationMail.php b/src/Mail/VerificationMail.php index b687af7..ab470c4 100644 --- a/src/Mail/VerificationMail.php +++ b/src/Mail/VerificationMail.php @@ -58,6 +58,7 @@ public function content(): Content 'currentHour' => now()->hour, 'user' => $this->verificationCode->subject, 'code' => $this->verificationCode->code, + 'type' => $this->verificationCode->for, 'content' => $this->content, ] ); diff --git a/src/Support/TwoFactorAuth.php b/src/Support/TwoFactorAuth.php index 4982698..f3e937e 100644 --- a/src/Support/TwoFactorAuth.php +++ b/src/Support/TwoFactorAuth.php @@ -354,6 +354,9 @@ public static function isEnabled(User $user): bool return $twoFaSettings->getBoolean('enabled'); } + /** + * True if 2FA should be enforced for a user. + */ public static function shouldEnforce(User $user): bool { $systemEnforced = static::isSystemEnforced(); @@ -379,6 +382,9 @@ public static function isCompanyEnforced(Company $company): bool return false; } + /** + * True if 2FA is enforced system wide. + */ public static function isSystemEnforced(): bool { $twoFaSettings = static::getTwoFaConfiguration(); @@ -404,7 +410,7 @@ public static function start(string $identity, int $tokenLength = 40): ?string if ($user) { $token = Str::random($tokenLength); - $twoFaSessionKey = static::createTwoFaSessionKey($user, $token, true); + $twoFaSessionKey = static::createTwoFaSessionKey($user, $token); return static::encryptSessionKey($twoFaSessionKey, $user->uuid); } @@ -579,13 +585,12 @@ public static function forgetTwoFaSession(string $token, string $identity): bool * * @return string the Two-Factor Authentication session key */ - private static function createTwoFaSessionKey(User $user, string $token, bool $storeInCache = false, int $expiresAfter = 600): string + private static function createTwoFaSessionKey(User $user, string $token, bool $storeInCache = true, int $expiresAfter = 600): string { $twoFaSessionKey = 'two_fa_session:' . $user->uuid . ':' . $token; if ($storeInCache) { - $expirationTime = Carbon::now()->addSeconds($expiresAfter)->timestamp; - Redis::set($twoFaSessionKey, $user->uuid, 'EX', $expirationTime); + Redis::set($twoFaSessionKey, $user->uuid, 'EX', now()->addSeconds($expiresAfter)->timestamp); } return $twoFaSessionKey; diff --git a/src/routes.php b/src/routes.php index 5fc95c9..2ece2bb 100644 --- a/src/routes.php +++ b/src/routes.php @@ -190,7 +190,7 @@ function ($router, $controller) { $router->fleetbaseRoutes( 'two-fa', function ($router, $controller) { - $router->post('config', $controller('saveSystemConfig')); + $router->post('config', $controller('saveSystemConfig'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]); $router->get('config', $controller('getSystemConfig'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]); $router->get('enforce', $controller('shouldEnforce'))->middleware([Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class]); } diff --git a/views/mail/verification.blade.php b/views/mail/verification.blade.php index 7ff0178..0b6df5f 100644 --- a/views/mail/verification.blade.php +++ b/views/mail/verification.blade.php @@ -18,8 +18,10 @@
@endif -@component('mail::button', ['url' => \Fleetbase\Support\Utils::consoleUrl('onboard/verify-email', ['hello' => base64_encode($user->uuid), 'code' => $code ])]) - Verify Email -@endcomponent +@if($type === 'email_verification') + @component('mail::button', ['url' => \Fleetbase\Support\Utils::consoleUrl('onboard/verify-email', ['hello' => base64_encode($user->uuid), 'code' => $code ])]) + Verify Email + @endcomponent +@endif From 69926d664bf9a4791c8bfa9eafe0012ec0d22499 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 22 May 2024 16:56:06 +0800 Subject: [PATCH 2/8] added tag for model caching --- config/laravel-model-caching.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/laravel-model-caching.php b/config/laravel-model-caching.php index 62f2658..3856f16 100644 --- a/config/laravel-model-caching.php +++ b/config/laravel-model-caching.php @@ -1,7 +1,7 @@ '', + 'cache-prefix' => 'fleetbase-model-cache', 'enabled' => env('MODEL_CACHE_ENABLED', true), From 120e70fd9251d8d780e37a43a47d2739e368f77b Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 22 May 2024 16:59:25 +0800 Subject: [PATCH 3/8] ran linter and only flush cache on bulk insert if method available --- src/Http/Requests/ImportRequest.php | 2 +- src/Traits/Insertable.php | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Http/Requests/ImportRequest.php b/src/Http/Requests/ImportRequest.php index cea5116..8dd1fe6 100644 --- a/src/Http/Requests/ImportRequest.php +++ b/src/Http/Requests/ImportRequest.php @@ -22,7 +22,7 @@ public function authorize() public function rules() { return [ - 'files' => ['required', 'array'] + 'files' => ['required', 'array'], ]; } } diff --git a/src/Traits/Insertable.php b/src/Traits/Insertable.php index 5d5f0c0..ea36de4 100644 --- a/src/Traits/Insertable.php +++ b/src/Traits/Insertable.php @@ -43,7 +43,12 @@ public static function bulkInsert(array $rows = []): bool } $result = static::insert($rows); - $model->flushCache(); + + // flush cache + if (method_exists($model, 'flushCache')) { + $model->flushCache(); + } + return $result; } } From 48c977a19b5dcaad0e8522397ab8c880227580c4 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Tue, 28 May 2024 18:36:35 +0800 Subject: [PATCH 4/8] added import validation, will refactor better later --- src/Models/File.php | 22 ++++++++++++++++++++++ src/Support/ImportValidator.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/Support/ImportValidator.php diff --git a/src/Models/File.php b/src/Models/File.php index 0956e6d..2869dab 100644 --- a/src/Models/File.php +++ b/src/Models/File.php @@ -4,6 +4,7 @@ use Fleetbase\Casts\Json; use Fleetbase\Casts\PolymorphicType; +use Fleetbase\Support\ImportValidator; use Fleetbase\Support\Utils; use Fleetbase\Traits\HasApiModelBehavior; use Fleetbase\Traits\HasPublicId; @@ -11,6 +12,7 @@ use Fleetbase\Traits\SendsWebhooks; use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Mimey\MimeTypes; @@ -417,4 +419,24 @@ public static function randomFileNameFromRequest($request, ?string $extension = return static::randomFileName($extension); } + + public static function validImports(array $ids = []): Collection + { + if (empty($ids)) { + $ids = request()->array('files'); + } + + $files = File::whereIn('uuid', $ids)->get(); + + return $files->filter(function ($file) { + return !ImportValidator::isValid($file); + }); + } + + public static function importsFromRequest(Request $request): Collection + { + $ids = $request->array('files'); + + return static::validImports($ids); + } } diff --git a/src/Support/ImportValidator.php b/src/Support/ImportValidator.php new file mode 100644 index 0000000..490c82d --- /dev/null +++ b/src/Support/ImportValidator.php @@ -0,0 +1,31 @@ +validFileTypes; + } + + public function validateFile(File $file): bool + { + return !Str::endsWith($file->path, $this->validFileTypes); + } + + public function validateFilePath(string $path): bool + { + return !Str::endsWith($path, $this->validFileTypes); + } + + public static function isValid(File $file): bool + { + return (new static())->validateFile($file); + } +} From 9ec495750daef2f8f4d979596f7cac4e1228cbb8 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 29 May 2024 12:06:34 +0800 Subject: [PATCH 5/8] improved validation on import request, validating the actual file extensions for import, added utility method to file model to resolve files from request, and a new request macro to get resolved files from ids --- .php-cs-fixer.php | 1 + src/Expansions/Request.php | 119 +++++++++++----------------- src/Http/Requests/ImportRequest.php | 18 ++++- src/Models/File.php | 34 ++++---- 4 files changed, 83 insertions(+), 89 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index a59a12d..b117b66 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -10,6 +10,7 @@ $rules = [ '@Symfony' => true, 'phpdoc_no_empty_return' => false, + 'phpdoc_to_comment' => false, 'array_syntax' => ['syntax' => 'short'], 'yoda_style' => false, 'binary_operator_spaces' => [ diff --git a/src/Expansions/Request.php b/src/Expansions/Request.php index c6044db..ded0166 100644 --- a/src/Expansions/Request.php +++ b/src/Expansions/Request.php @@ -4,17 +4,20 @@ use Fleetbase\Build\Expansion; use Fleetbase\Models\Company; +use Fleetbase\Models\File; use Illuminate\Support\Str; /** + * Expands the Illuminate\Http\Request class with additional helper methods. + * * @mixin \Illuminate\Support\Facades\Request */ class Request implements Expansion { /** - * Get the target class to expand. + * Specifies the class this expansion targets. * - * @return string|Class + * @return string the name of the class to expand */ public static function target() { @@ -22,9 +25,9 @@ public static function target() } /** - * Extends Request to find the current organization/company. + * Retrieves the current company based on the session data. * - * @return Company|null + * @return \Closure returns a closure that resolves to a Company instance or null */ public function company() { @@ -39,21 +42,15 @@ public function company() } /** - * Iterates request params until a param is found. + * Attempts to retrieve the first available parameter from a specified set. * - * @return Closure + * @return \Closure returns a closure that checks for the presence of parameters + * in a specific order and returns the value of the first parameter found */ public function or() { - /* - * Iterates request params until a param is found. - * - * @param array $params - * @param mixed $default - * @return mixed - */ return function (array $params = [], $default = null) { - /* @var \Illuminate\Http\Request $this */ + /** @var \Illuminate\Http\Request $this */ foreach ($params as $param) { if ($this->has($param)) { return $this->input($param); @@ -65,18 +62,13 @@ public function or() } /** - * Retrieve input from the request as a array. + * Converts a specified request parameter into an array by splitting it by commas. * - * @return Closure + * @return \Closure returns a closure that splits a string parameter into an array, + * or directly returns the array parameter */ public function array() { - /* - * Retrieve input from the request as a array. - * - * @param string $param - * @return array - */ return function (string $param) { /** @var \Illuminate\Http\Request $this */ if (is_string($this->input($param)) && Str::contains($this->input($param), ',')) { @@ -88,52 +80,40 @@ public function array() } /** - * Check if param is string value. + * Checks if a specified parameter is a string. * - * @return Closure + * @return \Closure returns a closure that determines if a parameter is a string */ public function isString() { return function ($param) { - /* - * Context. - * - * @var \Illuminate\Support\Facades\Request $this - */ + /** @var \Illuminate\Http\Request $this */ return $this->has($param) && is_string($this->input($param)); }; } /** - * Check if param is array value. + * Checks if a specified parameter is an array. * - * @return Closure + * @return \Closure returns a closure that determines if a parameter is an array */ public function isArray() { return function ($param) { - /* - * Context. - * - * @var \Illuminate\Support\Facades\Request $this - */ + /** @var \Illuminate\Http\Request $this */ return $this->has($param) && is_array($this->input($param)); }; } /** - * Check value exists in request array param. + * Checks if a specific value exists within an array parameter. * - * @return Closure + * @return \Closure returns a closure that checks if a value is present in an array parameter */ public function inArray() { return function ($param, $needle) { - /** - * Context. - * - * @var \Illuminate\Support\Facades\Request $this - */ + /** @var \Illuminate\Http\Request $this */ $haystack = (array) $this->input($param, []); if (is_array($haystack)) { @@ -145,55 +125,39 @@ public function inArray() } /** - * Retrieve input from the request as a integer. + * Retrieves an integer value from a specified request parameter. * - * @return Closure + * @return \Closure returns a closure that fetches an integer from the request */ public function integer() { - /* - * Retrieve input from the request as a integer. - * - * @param string $key - * @return array - */ return function (string $key, $default = 0) { - /* @var \Illuminate\Http\Request $this */ + /** @var \Illuminate\Http\Request $this */ return intval($this->input($key, $default)); }; } /** - * Removes a param from the request. + * Removes a specified parameter from the request. * - * @return Closure + * @return \Closure returns a closure that removes a parameter from the request */ public function removeParam() { - /* - * Retrieve input from the request as a integer. - * - * @param string $key - * @return array - */ return function (string $key) { - /* @var \Illuminate\Http\Request $this */ + /** @var \Illuminate\Http\Request $this */ return $this->request->remove($key); }; } /** - * Retrieves the search query parameter. + * Retrieves the search query from the request, with prioritization over multiple possible keys. * - * @return Closure + * @return \Closure returns a closure that fetches a search query parameter, prioritizing + * specific keys and handling potential casing and encoding issues */ public function searchQuery() { - /* - * Retrieve the search query parameter. - * - * @return string - */ return function () { /** @var \Illuminate\Http\Request $this */ $searchQueryParam = $this->or(['query', 'searchQuery', 'nestedQuery']); @@ -207,9 +171,22 @@ public function searchQuery() } /** - * Returns all Fleetbase global filters. + * Fetches File models based on UUIDs provided in a specified request parameter. * - * @return Closure + * @return \Closure returns a closure that retrieves a collection of File models from UUIDs specified in the request + */ + public function resolveFilesFromIds() + { + return function (string $param = 'files') { + /** @var \Illuminate\Http\Request $this */ + return File::fromRequest($this, $param); + }; + } + + /** + * Retrieves all request parameters except for those related to Fleetbase's global filters. + * + * @return \Closure returns a closure that filters out global parameters and retrieves the rest */ public function getFilters() { @@ -244,7 +221,7 @@ public function getFilters() ]; $filters = is_array($additionalFilters) ? array_merge($defaultFilters, $additionalFilters) : $defaultFilters; - /* @var \Illuminate\Http\Request $this */ + /** @var \Illuminate\Http\Request $this */ return $this->except($filters); }; } diff --git a/src/Http/Requests/ImportRequest.php b/src/Http/Requests/ImportRequest.php index 8dd1fe6..a1cc5bc 100644 --- a/src/Http/Requests/ImportRequest.php +++ b/src/Http/Requests/ImportRequest.php @@ -2,6 +2,8 @@ namespace Fleetbase\Http\Requests; +use Fleetbase\Models\File; + class ImportRequest extends FleetbaseRequest { /** @@ -22,7 +24,21 @@ public function authorize() public function rules() { return [ - 'files' => ['required', 'array'], + 'files' => ['required', 'array', 'exists:files,uuid', + function ($attribute, $value, $fail) { + foreach ($value as $uuid) { + $file = File::where('uuid', $uuid)->first(); + if (!$file) { + return $fail('One of the files sent for import is invalid.'); + } + + $validExtensions = ['csv', 'tsv', 'xls', 'xlsx']; + $extension = pathinfo($file->path, PATHINFO_EXTENSION); + if (!in_array($extension, $validExtensions)) { + return $fail('The file (' . $file->original_filename . ') format with the extension ' . $extension . ' is not valid for import.'); + } + } + }], ]; } } diff --git a/src/Models/File.php b/src/Models/File.php index 2869dab..2589602 100644 --- a/src/Models/File.php +++ b/src/Models/File.php @@ -4,7 +4,6 @@ use Fleetbase\Casts\Json; use Fleetbase\Casts\PolymorphicType; -use Fleetbase\Support\ImportValidator; use Fleetbase\Support\Utils; use Fleetbase\Traits\HasApiModelBehavior; use Fleetbase\Traits\HasPublicId; @@ -420,23 +419,24 @@ public static function randomFileNameFromRequest($request, ?string $extension = return static::randomFileName($extension); } - public static function validImports(array $ids = []): Collection - { - if (empty($ids)) { - $ids = request()->array('files'); - } - - $files = File::whereIn('uuid', $ids)->get(); - - return $files->filter(function ($file) { - return !ImportValidator::isValid($file); - }); - } - - public static function importsFromRequest(Request $request): Collection + /** + * Retrieves a collection of files based on UUIDs provided via a request. + * + * This method extracts an array of UUIDs from the request and retrieves + * corresponding file models. It is static, allowing it to be called on the class itself + * without needing an instance of the class. + * + * @param Request $request the HTTP request containing the 'files' array with UUIDs + * @param string $param the Param which should hold the array of files + * + * @return Collection a collection of File models that match the provided UUIDs + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException if no model is found + */ + public static function fromRequest(Request $request, string $param = 'files'): Collection { - $ids = $request->array('files'); + $ids = $request->array($param); - return static::validImports($ids); + return static::whereIn('uuid', $ids)->get(); } } From ccbe59e7304c100dacf43afa2f35a7f64aa83c58 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 29 May 2024 12:07:12 +0800 Subject: [PATCH 6/8] removed importvalidator class --- src/Support/ImportValidator.php | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 src/Support/ImportValidator.php diff --git a/src/Support/ImportValidator.php b/src/Support/ImportValidator.php deleted file mode 100644 index 490c82d..0000000 --- a/src/Support/ImportValidator.php +++ /dev/null @@ -1,31 +0,0 @@ -validFileTypes; - } - - public function validateFile(File $file): bool - { - return !Str::endsWith($file->path, $this->validFileTypes); - } - - public function validateFilePath(string $path): bool - { - return !Str::endsWith($path, $this->validFileTypes); - } - - public static function isValid(File $file): bool - { - return (new static())->validateFile($file); - } -} From a637e7e7d7323cf4e7146c54e650da805bae5302 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 29 May 2024 12:25:36 +0800 Subject: [PATCH 7/8] added middleware to clear responsecache after delete requests --- src/Http/Middleware/ClearCacheAfterDelete.php | 23 +++++++++++++++++++ src/Providers/CoreServiceProvider.php | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 src/Http/Middleware/ClearCacheAfterDelete.php diff --git a/src/Http/Middleware/ClearCacheAfterDelete.php b/src/Http/Middleware/ClearCacheAfterDelete.php new file mode 100644 index 0000000..df022f7 --- /dev/null +++ b/src/Http/Middleware/ClearCacheAfterDelete.php @@ -0,0 +1,23 @@ +isMethod('delete')) { + // Clear the cache after the response has been sent + ResponseCache::clear(); + } + + return $response; + } +} diff --git a/src/Providers/CoreServiceProvider.php b/src/Providers/CoreServiceProvider.php index cd0f734..df19ffc 100644 --- a/src/Providers/CoreServiceProvider.php +++ b/src/Providers/CoreServiceProvider.php @@ -45,6 +45,7 @@ class CoreServiceProvider extends ServiceProvider \Fleetbase\Http\Middleware\SetupFleetbaseSession::class, \Fleetbase\Http\Middleware\TrackPresence::class, \Spatie\ResponseCache\Middlewares\CacheResponse::class, + \Fleetbase\Http\Middleware\ClearCacheAfterDelete::class, ], 'fleetbase.api' => [ 'throttle:60,1', @@ -53,6 +54,7 @@ class CoreServiceProvider extends ServiceProvider \Illuminate\Routing\Middleware\SubstituteBindings::class, \Fleetbase\Http\Middleware\LogApiRequests::class, \Spatie\ResponseCache\Middlewares\CacheResponse::class, + \Fleetbase\Http\Middleware\ClearCacheAfterDelete::class, ], ]; From d99b707c467ce6e46134cf43e616ce3f435e4ba7 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 30 May 2024 18:34:37 +0800 Subject: [PATCH 8/8] patches for dev logging, and additional useful user functions --- src/Http/Requests/OnboardRequest.php | 2 +- src/Jobs/LogApiRequest.php | 3 +++ src/Models/ApiCredential.php | 10 ++++++++ src/Models/ApiEvent.php | 2 ++ src/Models/ApiRequestLog.php | 2 ++ src/Models/User.php | 37 ++++++++++++++++++++++++++++ src/Support/Auth.php | 3 +++ src/Types/Country.php | 15 +++++++++-- 8 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/Http/Requests/OnboardRequest.php b/src/Http/Requests/OnboardRequest.php index ad68fc5..2897f46 100644 --- a/src/Http/Requests/OnboardRequest.php +++ b/src/Http/Requests/OnboardRequest.php @@ -14,7 +14,7 @@ class OnboardRequest extends FleetbaseRequest * * @return array */ - protected $excludedWords = ['test', 'testing', 'example', 'trial', 'trialing', 'asdf', '1234', 'asdas', 'dsdsds']; + protected $excludedWords = ['test', 'test123', 'abctest', 'testing', 'example', 'trial', 'trialing', 'asdf', '1234', 'asdas', 'dsdsds', 'dummy', 'xxxx', 'aaa', 'demo', 'zzz', 'zzzz', 'none']; /** * Determine if the user is authorized to make this request. diff --git a/src/Jobs/LogApiRequest.php b/src/Jobs/LogApiRequest.php index e6d85d2..eef590d 100644 --- a/src/Jobs/LogApiRequest.php +++ b/src/Jobs/LogApiRequest.php @@ -14,6 +14,7 @@ use Illuminate\Queue\SerializesModels; use Illuminate\Support\Arr; use Illuminate\Support\Str; +use Spatie\ResponseCache\Facades\ResponseCache; class LogApiRequest implements ShouldQueue { @@ -58,6 +59,8 @@ public function handle() { // Log::info('Logging API Request ' . print_r($this->payload, true)); ApiRequestLog::on($this->dbConnection)->create($this->payload); + // Clear response cache + ResponseCache::clear(); } /** diff --git a/src/Models/ApiCredential.php b/src/Models/ApiCredential.php index 7ec81b3..e717f04 100644 --- a/src/Models/ApiCredential.php +++ b/src/Models/ApiCredential.php @@ -172,4 +172,14 @@ public static function generateKeys($encode, $testKey = false) 'secret' => $hash, ]; } + + /** + * Update the datetime of the last usage. + * + * @return bool + */ + public function trackLastUsed() + { + return $this->update(['last_used_at' => now()]); + } } diff --git a/src/Models/ApiEvent.php b/src/Models/ApiEvent.php index 73e87ab..98c736c 100644 --- a/src/Models/ApiEvent.php +++ b/src/Models/ApiEvent.php @@ -5,12 +5,14 @@ use Fleetbase\Casts\Json; use Fleetbase\Traits\Filterable; use Fleetbase\Traits\HasApiModelBehavior; +use Fleetbase\Traits\HasPublicId; use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\Searchable; class ApiEvent extends Model { use HasUuid; + use HasPublicId; use HasApiModelBehavior; use Searchable; use Filterable; diff --git a/src/Models/ApiRequestLog.php b/src/Models/ApiRequestLog.php index bbd9c83..84b7719 100644 --- a/src/Models/ApiRequestLog.php +++ b/src/Models/ApiRequestLog.php @@ -5,12 +5,14 @@ use Fleetbase\Casts\Json; use Fleetbase\Traits\Filterable; use Fleetbase\Traits\HasApiModelBehavior; +use Fleetbase\Traits\HasPublicId; use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\Searchable; class ApiRequestLog extends Model { use HasUuid; + use HasPublicId; use HasApiModelBehavior; use Searchable; use Filterable; diff --git a/src/Models/User.php b/src/Models/User.php index 76d7acb..d5fb6a2 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -775,6 +775,25 @@ public static function applyUserInfoFromRequest($request, array $attributes = [] return $attributes; } + /** + * Create a new User instance with enriched attributes from the request. + * + * This static method constructs a new User object using information obtained from + * a request object. It enhances the initial user attributes with additional details + * such as country, timezone, and IP-related metadata by leveraging the + * applyUserInfoFromRequest() method. This method is ideal for initializing a user with + * comprehensive details at the point of creation, particularly during registration processes. + * + * @param \Illuminate\Http\Request $request the request object containing user's IP address and possibly other details + * @param array $attributes an optional array of initial attributes that may be provided for the user + * + * @return User returns the newly created User instance with enriched attributes + */ + public static function newUserWithRequestInfo($request, $attributes = []): User + { + return new User(static::applyUserInfoFromRequest($request, $attributes)); + } + /** * Sets user information from the request on the current User model instance. * @@ -804,11 +823,29 @@ public function setUserInfoFromRequest($request, bool $save = false): User return $this; } + /** + * Retrieve the last seen timestamp of the user. + * + * This method acts as an accessor for the 'lastSeenAt' attribute of the User model. + * It returns the datetime when the user was last active in the system. This can be + * used to display the last seen status or to calculate if the user is offline. + * + * @return \Carbon\Carbon|null returns the Carbon instance for the last seen timestamp or null if not set + */ public function getLastSeenAtAttribute() { return $this->lastSeenAt(); } + /** + * Check if the user is currently online. + * + * This accessor method for the 'isOnline' attribute determines if the user is considered + * online based on certain criteria like their last activity timestamp. It leverages the + * isOnline() method, which should contain the logic to ascertain the user's online status. + * + * @return bool returns true if the user is online, otherwise false + */ public function getIsOnlineAttribute() { return $this->isOnline(); diff --git a/src/Support/Auth.php b/src/Support/Auth.php index a84183d..d6eec69 100644 --- a/src/Support/Auth.php +++ b/src/Support/Auth.php @@ -65,6 +65,9 @@ public static function setSession($user = null, $login = false): bool session(['is_admin' => $user->isAdmin()]); } + // track last usage of api credential + $apiCredential->trackLastUsed(); + return true; } diff --git a/src/Types/Country.php b/src/Types/Country.php index 736f1c8..db36297 100644 --- a/src/Types/Country.php +++ b/src/Types/Country.php @@ -126,7 +126,18 @@ public function only($keys = []): array $key = Arr::first(array_keys($key)); } - $result[$as] = strpos($key, '.') > 0 ? Utils::get($this, $key) : $this->{$key}; + if (!is_string($key)) { + continue; + } + + if (strpos($key, '.') > 0) { + $result[$as] = Utils::get($this, $key); + continue; + } + + if (isset($this->{$key})) { + $result[$as] = $this->{$key}; + } } return $result; @@ -232,7 +243,7 @@ function ($country) use ($query) { strtolower($country->getCode()) === $query, strtolower($country->getCca2()) === $query, Str::contains(strtolower($country->getAbbrev()), $query), - Str::contains(strtolower($country->getName()), $query), + // Str::contains(strtolower($country->getName()), $query), ]; return count(array_filter($matches));