From dd85782a0ddebf2067200f9f040f3d50e99eecdd Mon Sep 17 00:00:00 2001 From: Miguel Angel Date: Wed, 17 Jan 2024 15:56:34 -0400 Subject: [PATCH 01/11] feat: add 2fa setting in groups --- .../Controllers/Admin/GroupController.php | 9 +++++- .../Http/Controllers/Api/GroupController.php | 6 ++++ .../Controllers/Api/SettingController.php | 7 +++++ ProcessMaker/Models/Group.php | 1 + ...7_183702_add_2fa_field_to_groups_table.php | 28 +++++++++++++++++++ resources/views/admin/groups/edit.blade.php | 24 ++++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2024_01_17_183702_add_2fa_field_to_groups_table.php diff --git a/ProcessMaker/Http/Controllers/Admin/GroupController.php b/ProcessMaker/Http/Controllers/Admin/GroupController.php index 40e5e08720..0c54e0dbcf 100644 --- a/ProcessMaker/Http/Controllers/Admin/GroupController.php +++ b/ProcessMaker/Http/Controllers/Admin/GroupController.php @@ -34,6 +34,12 @@ public function edit(Group $group) $all_permissions = Permission::all(); $permissionGroups = $all_permissions->sortBy('title')->groupBy('group')->sortKeys(); + // Get the 2FA settings + $settings = [ + '2fa_enabled' => config('password-policies.2fa_enabled', false), + '2fa_methods' => config('password-policies.2fa_method', []), + ]; + $addons = $this->getPluginAddons('edit', compact(['group'])); return view('admin.groups.edit', compact( @@ -41,7 +47,8 @@ public function edit(Group $group) 'permissionNames', 'all_permissions', 'permissionGroups', - 'addons' + 'addons', + 'settings', )); } diff --git a/ProcessMaker/Http/Controllers/Api/GroupController.php b/ProcessMaker/Http/Controllers/Api/GroupController.php index d2ffca4072..804bd66e30 100644 --- a/ProcessMaker/Http/Controllers/Api/GroupController.php +++ b/ProcessMaker/Http/Controllers/Api/GroupController.php @@ -138,6 +138,12 @@ public function index(Request $request) public function store(Request $request) { $request->validate(Group::rules()); + + // Check if 2FA is enabled and set the enabled_2fa flag + if (config('password-policies.2fa_enabled', false)) { + $request->merge(['enabled_2fa' => true]); + } + $group = new Group(); $group->fill($request->input()); $group->saveOrFail(); diff --git a/ProcessMaker/Http/Controllers/Api/SettingController.php b/ProcessMaker/Http/Controllers/Api/SettingController.php index 0d1c02b901..4f788ba795 100644 --- a/ProcessMaker/Http/Controllers/Api/SettingController.php +++ b/ProcessMaker/Http/Controllers/Api/SettingController.php @@ -11,6 +11,7 @@ use ProcessMaker\Http\Resources\ApiCollection; use ProcessMaker\Http\Resources\ApiResource; use ProcessMaker\Jobs\ImportSettings; +use ProcessMaker\Models\Group; use ProcessMaker\Models\Setting; use Throwable; @@ -211,6 +212,12 @@ public function update(Setting $setting, Request $request) $original = array_intersect_key($setting->getOriginal(), $setting->getDirty()); $setting->save(); + if ($setting->key === 'password-policies.2fa_enabled') { + // Update all groups with the new 2FA setting + Group::where('enabled_2fa', '!=', $setting->config) + ->update(['enabled_2fa' => $setting->config]); + } + // Register the Event SettingsUpdated::dispatch($setting, $setting->getChanges(), $original); diff --git a/ProcessMaker/Models/Group.php b/ProcessMaker/Models/Group.php index b3c49ea7ad..c6ee3f89e1 100644 --- a/ProcessMaker/Models/Group.php +++ b/ProcessMaker/Models/Group.php @@ -50,6 +50,7 @@ class Group extends ProcessMakerModel 'description', 'manager_id', 'status', + 'enabled_2fa', ]; public static function rules($existing = null) diff --git a/database/migrations/2024_01_17_183702_add_2fa_field_to_groups_table.php b/database/migrations/2024_01_17_183702_add_2fa_field_to_groups_table.php new file mode 100644 index 0000000000..f19ab100a9 --- /dev/null +++ b/database/migrations/2024_01_17_183702_add_2fa_field_to_groups_table.php @@ -0,0 +1,28 @@ +boolean('enabled_2fa')->default(false)->after('status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('groups', function (Blueprint $table) { + $table->dropColumn('enabled_2fa'); + }); + } +}; diff --git a/resources/views/admin/groups/edit.blade.php b/resources/views/admin/groups/edit.blade.php index 9edcdaaaf2..4d514426c3 100644 --- a/resources/views/admin/groups/edit.blade.php +++ b/resources/views/admin/groups/edit.blade.php @@ -67,6 +67,30 @@ 'v-bind:class' => '{\'form-control\':true, \'is-invalid\':errors.status}']) !!} + + @if ($settings['2fa_enabled']) +
+
+ {!! Form::checkbox('enabled_2fa', 1, null, [ + 'id' => 'enabled_2fa', + 'class' => 'custom-control-input', + 'v-model' => 'formData.enabled_2fa', + ]) !!} + + {!! Form::label('enabled_2fa', __('Two Factor Authentication'), [ + 'class' => 'custom-control-label', + 'for' => 'enabled_2fa', + ]) !!} +
+ + +
+ @endif + @isset($addons) @foreach ($addons as $addon) {!! __($addon['content']) !!} From 657cc6db28c735c30f668e5c1fb4aa3766a10913 Mon Sep 17 00:00:00 2001 From: TinCodes Date: Wed, 17 Jan 2024 16:14:48 -0400 Subject: [PATCH 02/11] Fixed console error --- resources/js/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index 261a852da8..17d5629940 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -297,7 +297,7 @@ if (window.Processmaker && window.Processmaker.broadcasting) { if (userID) { // Session timeout - const timeoutScript = document.head.querySelector("meta[name=\"timeout-worker\"]").content; + const timeoutScript = document.head.querySelector("meta[name=\"timeout-worker\"]")?.content; window.ProcessMaker.AccountTimeoutLength = parseInt(eval(document.head.querySelector("meta[name=\"timeout-length\"]").content)); window.ProcessMaker.AccountTimeoutWarnSeconds = parseInt(document.head.querySelector("meta[name=\"timeout-warn-seconds\"]").content); window.ProcessMaker.AccountTimeoutEnabled = document.head.querySelector("meta[name=\"timeout-enabled\"]") ? parseInt(document.head.querySelector("meta[name=\"timeout-enabled\"]").content) : 1; From acdfa3a20b5dfbf3470eee896385b5a517da9dc2 Mon Sep 17 00:00:00 2001 From: Miguel Angel Date: Thu, 18 Jan 2024 14:18:21 -0400 Subject: [PATCH 03/11] feat: check 2fa by group --- .../Auth/TwoFactorAuthController.php | 30 +++++++++++++++++++ .../Middleware/TwoFactorAuthentication.php | 3 +- ProcessMaker/Models/Group.php | 4 +++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php b/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php index 693b059a3d..ca3bfb9685 100644 --- a/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php +++ b/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php @@ -208,4 +208,34 @@ private function testSmsServer() } return true; } + + /** + * Check if 2FA is enabled for the current user based on the groups he belongs to + * + * @return bool + */ + public static function check2faByGroups() + { + try { + $user = auth()->user(); + $userGroups = $user->groups; + $groupsWith2fa = $userGroups->where('enabled_2fa', true); + $groupsWithout2fa = $userGroups->where('enabled_2fa', false); + + // Check if the only group has 2fa enabled, if so, ask for 2fa + $hasSingleGroupWith2fa = $userGroups->count() === 1 && $groupsWith2fa->count() === 1; + // Check if at least one group has 2fa enabled, if so, ask for 2fa + $hasMultipleGroupsWithAtLeastOne2fa = $userGroups->count() > 1 && $groupsWith2fa->count() > 0; + // Check if all groups don't have 2fa enabled or if the user doesn't belong to any group, if so, ask for 2fa + $allGroupsWithout2fa = $userGroups->count() === $groupsWithout2fa->count(); + + if ($hasSingleGroupWith2fa || $hasMultipleGroupsWithAtLeastOne2fa || $allGroupsWithout2fa) { + return true; + } + } catch (Exception $e) { + session()->put(self::TFA_ERROR, $e->getMessage()); + } + + return false; + } } diff --git a/ProcessMaker/Http/Middleware/TwoFactorAuthentication.php b/ProcessMaker/Http/Middleware/TwoFactorAuthentication.php index 5a0e7e37a7..25dc517d45 100644 --- a/ProcessMaker/Http/Middleware/TwoFactorAuthentication.php +++ b/ProcessMaker/Http/Middleware/TwoFactorAuthentication.php @@ -19,7 +19,8 @@ public function handle($request, Closure $next) // Check if 2FA is enabled, a method is set, and the current session is not yet validated if (config('password-policies.2fa_enabled', false) && !empty(config('password-policies.2fa_method', [])) && - !session()->get(TwoFactorAuthController::TFA_VALIDATED, false) + !session()->get(TwoFactorAuthController::TFA_VALIDATED, false) && + TwoFactorAuthController::check2faByGroups() ) { // If not validated display the 2FA code screen return redirect()->route('2fa'); diff --git a/ProcessMaker/Models/Group.php b/ProcessMaker/Models/Group.php index c6ee3f89e1..6d7948debe 100644 --- a/ProcessMaker/Models/Group.php +++ b/ProcessMaker/Models/Group.php @@ -53,6 +53,10 @@ class Group extends ProcessMakerModel 'enabled_2fa', ]; + protected $casts = [ + 'enabled_2fa' => 'boolean', + ]; + public static function rules($existing = null) { $unique = Rule::unique('groups')->ignore($existing); From 61cfc386c40c27ac45e6023fbba5fc9d45dc78bf Mon Sep 17 00:00:00 2001 From: TinCodes Date: Thu, 18 Jan 2024 15:02:37 -0400 Subject: [PATCH 04/11] Additional optional chainings made --- resources/js/bootstrap.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index 17d5629940..45bca6ed9e 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -93,7 +93,7 @@ window.Vue.component("filter-table", FilterTable); let translationsLoaded = false; const mdates = JSON.parse( - document.head.querySelector("meta[name=\"i18n-mdate\"]").content, + document.head.querySelector("meta[name=\"i18n-mdate\"]")?.content, ); // Make $t available to all vue instances @@ -270,9 +270,9 @@ if (appUrl) { if (userID) { window.ProcessMaker.user = { id: userID.content, - datetime_format: formatDate.content, - calendar_format: formatDate.content, - timezone: timezone.content, + datetime_format: formatDate?.content, + calendar_format: formatDate?.content, + timezone: timezone?.content, fullName: userFullName?.content, avatar: userAvatar?.content, }; @@ -298,9 +298,9 @@ if (window.Processmaker && window.Processmaker.broadcasting) { if (userID) { // Session timeout const timeoutScript = document.head.querySelector("meta[name=\"timeout-worker\"]")?.content; - window.ProcessMaker.AccountTimeoutLength = parseInt(eval(document.head.querySelector("meta[name=\"timeout-length\"]").content)); - window.ProcessMaker.AccountTimeoutWarnSeconds = parseInt(document.head.querySelector("meta[name=\"timeout-warn-seconds\"]").content); - window.ProcessMaker.AccountTimeoutEnabled = document.head.querySelector("meta[name=\"timeout-enabled\"]") ? parseInt(document.head.querySelector("meta[name=\"timeout-enabled\"]").content) : 1; + window.ProcessMaker.AccountTimeoutLength = parseInt(eval(document.head.querySelector("meta[name=\"timeout-length\"]")?.content)); + window.ProcessMaker.AccountTimeoutWarnSeconds = parseInt(document.head.querySelector("meta[name=\"timeout-warn-seconds\"]")?.content); + window.ProcessMaker.AccountTimeoutEnabled = document.head.querySelector("meta[name=\"timeout-enabled\"]") ? parseInt(document.head.querySelector("meta[name=\"timeout-enabled\"]")?.content) : 1; window.ProcessMaker.AccountTimeoutWorker = new Worker(timeoutScript); window.ProcessMaker.AccountTimeoutWorker.addEventListener("message", (e) => { if (e.data.method === "countdown") { From ffa9ba308abd0e818f9af0b5e0de4efc56fbee9e Mon Sep 17 00:00:00 2001 From: Miguel Angel Date: Fri, 19 Jan 2024 08:32:47 -0400 Subject: [PATCH 05/11] feat: improve check2faByGroups method --- .../Auth/TwoFactorAuthController.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php b/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php index ca3bfb9685..90ae8b8eb2 100644 --- a/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php +++ b/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php @@ -217,17 +217,22 @@ private function testSmsServer() public static function check2faByGroups() { try { - $user = auth()->user(); - $userGroups = $user->groups; + $userGroups = auth()->user()->groups; + $groupCount = $userGroups->count(); + + if ($groupCount === 0) { + return true; + } + $groupsWith2fa = $userGroups->where('enabled_2fa', true); $groupsWithout2fa = $userGroups->where('enabled_2fa', false); // Check if the only group has 2fa enabled, if so, ask for 2fa - $hasSingleGroupWith2fa = $userGroups->count() === 1 && $groupsWith2fa->count() === 1; + $hasSingleGroupWith2fa = $groupCount === 1 && $groupsWith2fa->count() === 1; // Check if at least one group has 2fa enabled, if so, ask for 2fa - $hasMultipleGroupsWithAtLeastOne2fa = $userGroups->count() > 1 && $groupsWith2fa->count() > 0; - // Check if all groups don't have 2fa enabled or if the user doesn't belong to any group, if so, ask for 2fa - $allGroupsWithout2fa = $userGroups->count() === $groupsWithout2fa->count(); + $hasMultipleGroupsWithAtLeastOne2fa = $groupCount > 1 && $groupsWith2fa->count() > 0; + // Check if all groups don't have 2fa enabled, if so, ask for 2fa if the 2fa setting is enabled + $allGroupsWithout2fa = $groupCount > 1 && $groupsWithout2fa->count() === $groupCount; if ($hasSingleGroupWith2fa || $hasMultipleGroupsWithAtLeastOne2fa || $allGroupsWithout2fa) { return true; From 06e23c55239ea89525192ec937eafcb01faa2eae Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Fri, 19 Jan 2024 11:25:15 -0400 Subject: [PATCH 06/11] Remove methods as the mockup --- resources/views/admin/groups/edit.blade.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/resources/views/admin/groups/edit.blade.php b/resources/views/admin/groups/edit.blade.php index 4d514426c3..9f6ca3420c 100644 --- a/resources/views/admin/groups/edit.blade.php +++ b/resources/views/admin/groups/edit.blade.php @@ -82,12 +82,6 @@ 'for' => 'enabled_2fa', ]) !!} - -
    - @foreach ($settings['2fa_methods'] as $method) -
  • {{ $method }}
  • - @endforeach -
@endif From 50cf2991c67b2ccac615fc8d412d024e6d3888a6 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Fri, 19 Jan 2024 12:07:52 -0400 Subject: [PATCH 07/11] Hide 2FA if disabled for all groups of the User --- .../Http/Controllers/Admin/UserController.php | 2 ++ .../Auth/TwoFactorAuthController.php | 22 ++-------------- .../Http/Controllers/ProfileController.php | 3 ++- ProcessMaker/Models/User.php | 25 +++++++++++++++++++ .../views/shared/users/sidebar.blade.php | 2 +- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Admin/UserController.php b/ProcessMaker/Http/Controllers/Admin/UserController.php index eb4feeabae..aa156968c0 100644 --- a/ProcessMaker/Http/Controllers/Admin/UserController.php +++ b/ProcessMaker/Http/Controllers/Admin/UserController.php @@ -81,6 +81,7 @@ function ($result, $item) { $enabled2FA = config('password-policies.2fa_enabled', false); $global2FAEnabled = config('password-policies.2fa_method', []); $user->preferences_2fa = $user->getValid2FAPreferences(); + $is2FAEnabledForGroup = $user->in2FAGroupOrIndependent(); $addons = $this->getPluginAddons('edit', compact(['user'])); $addonsSettings = $this->getPluginAddons('edit.settings', compact(['user'])); @@ -99,6 +100,7 @@ function ($result, $item) { 'status', 'enabled2FA', 'global2FAEnabled', + 'is2FAEnabledForGroup', 'addons', 'addonsSettings', )); diff --git a/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php b/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php index 90ae8b8eb2..5a3c4b6bbc 100644 --- a/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php +++ b/ProcessMaker/Http/Controllers/Auth/TwoFactorAuthController.php @@ -217,26 +217,8 @@ private function testSmsServer() public static function check2faByGroups() { try { - $userGroups = auth()->user()->groups; - $groupCount = $userGroups->count(); - - if ($groupCount === 0) { - return true; - } - - $groupsWith2fa = $userGroups->where('enabled_2fa', true); - $groupsWithout2fa = $userGroups->where('enabled_2fa', false); - - // Check if the only group has 2fa enabled, if so, ask for 2fa - $hasSingleGroupWith2fa = $groupCount === 1 && $groupsWith2fa->count() === 1; - // Check if at least one group has 2fa enabled, if so, ask for 2fa - $hasMultipleGroupsWithAtLeastOne2fa = $groupCount > 1 && $groupsWith2fa->count() > 0; - // Check if all groups don't have 2fa enabled, if so, ask for 2fa if the 2fa setting is enabled - $allGroupsWithout2fa = $groupCount > 1 && $groupsWithout2fa->count() === $groupCount; - - if ($hasSingleGroupWith2fa || $hasMultipleGroupsWithAtLeastOne2fa || $allGroupsWithout2fa) { - return true; - } + $user = Auth::user(); + return $user->in2FAGroupOrIndependent(); } catch (Exception $e) { session()->put(self::TFA_ERROR, $e->getMessage()); } diff --git a/ProcessMaker/Http/Controllers/ProfileController.php b/ProcessMaker/Http/Controllers/ProfileController.php index 4ddff232ae..57f292dabb 100644 --- a/ProcessMaker/Http/Controllers/ProfileController.php +++ b/ProcessMaker/Http/Controllers/ProfileController.php @@ -54,12 +54,13 @@ function ($result, $item) { $enabled2FA = config('password-policies.2fa_enabled', false); $global2FAEnabled = config('password-policies.2fa_method', []); $currentUser->preferences_2fa = $currentUser->getValid2FAPreferences(); + $is2FAEnabledForGroup = $currentUser->in2FAGroupOrIndependent(); $addons = $this->getPluginAddons('edit', []); return view('profile.edit', compact('currentUser', 'states', 'timezones', 'countries', 'datetimeFormats', 'availableLangs', - 'status', 'enabled2FA', 'global2FAEnabled', 'addons')); + 'status', 'enabled2FA', 'global2FAEnabled', 'is2FAEnabledForGroup', 'addons')); } /** diff --git a/ProcessMaker/Models/User.php b/ProcessMaker/Models/User.php index fa5dcce80a..c1bc386e3d 100644 --- a/ProcessMaker/Models/User.php +++ b/ProcessMaker/Models/User.php @@ -2,6 +2,7 @@ namespace ProcessMaker\Models; +use Exception; use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -533,4 +534,28 @@ public function getValid2FAPreferences(): array return !empty($aux) ? array_values($aux) : $global2FAEnabled; } + + public function in2FAGroupOrIndependent() + { + $userGroups = $this->groups; + $groupCount = $userGroups->count(); + + if ($groupCount === 0) { + return true; + } + + $groupsWith2fa = $userGroups->where('enabled_2fa', true); + + // Check if the only group has 2fa enabled, if so, ask for 2fa + $hasSingleGroupWith2fa = $groupCount === 1 && $groupsWith2fa->count() === 1; + // Check if at least one group has 2fa enabled, if so, ask for 2fa + $hasMultipleGroupsWithAtLeastOne2fa = $groupCount > 1 && $groupsWith2fa->count() > 0; + // Check if all groups don't have 2fa enabled, if so, ask for 2fa if the 2fa setting is enabled + $independent = $groupCount === 0; + + if ($hasSingleGroupWith2fa || $hasMultipleGroupsWithAtLeastOne2fa || $independent) { + return true; + } + return false; + } } diff --git a/resources/views/shared/users/sidebar.blade.php b/resources/views/shared/users/sidebar.blade.php index 3e4e24cc06..b7c4dcae18 100644 --- a/resources/views/shared/users/sidebar.blade.php +++ b/resources/views/shared/users/sidebar.blade.php @@ -83,7 +83,7 @@ @endif - @if (config('password-policies.2fa_enabled', false) && count($global2FAEnabled) > 0) + @if (config('password-policies.2fa_enabled', false) && count($global2FAEnabled) > 0 && $is2FAEnabledForGroup)
{!! Form::label('preferences_2fa', __('Two Factor Authentication')) !!} Date: Fri, 19 Jan 2024 13:52:14 -0400 Subject: [PATCH 08/11] fix: session control block and user session listener --- ProcessMaker/Http/Middleware/SessionControlBlock.php | 5 +---- ProcessMaker/Listeners/UserSession.php | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ProcessMaker/Http/Middleware/SessionControlBlock.php b/ProcessMaker/Http/Middleware/SessionControlBlock.php index e7a0aa7ea2..4fc90ac78a 100644 --- a/ProcessMaker/Http/Middleware/SessionControlBlock.php +++ b/ProcessMaker/Http/Middleware/SessionControlBlock.php @@ -98,10 +98,7 @@ private function blockSessionByDevice(User $user, Request $request): bool $ip = $request->getClientIp() ?? $request->ip(); // Get the user's most recent session $session = $user->sessions() - ->where([ - ['is_active', true], - ['ip_address', '!=', $ip], - ]) + ->where('is_active', true) ->orderBy('created_at', 'desc') ->first(); diff --git a/ProcessMaker/Listeners/UserSession.php b/ProcessMaker/Listeners/UserSession.php index b04b04d213..a7e752029a 100644 --- a/ProcessMaker/Listeners/UserSession.php +++ b/ProcessMaker/Listeners/UserSession.php @@ -44,10 +44,7 @@ public function handle(object $event): void if ($configDevice === '2') { $user->sessions() - ->where([ - ['is_active', true], - ['ip_address', '!=', $ip], - ]) + ->where('is_active', true) ->where(function (Builder $query) use ($agentDevice, $agentDeviceType, $agentPlatform, $ip) { $query->where('device_name', '!=', $agentDevice) ->orWhere('device_type', '!=', $agentDeviceType) From 74669e620c77e16835e659b7223e87e551481b9d Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Thu, 18 Jan 2024 14:14:33 -0400 Subject: [PATCH 09/11] Define missing redirectTo variable --- resources/js/templates/assets.js | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/js/templates/assets.js b/resources/js/templates/assets.js index 0bdfb597bc..e0dabdc12d 100644 --- a/resources/js/templates/assets.js +++ b/resources/js/templates/assets.js @@ -11,6 +11,7 @@ new Vue({ name: "", responseId: null, request: {}, + redirectTo: null, }; }, mounted() { From 3683890fbd40ca1820e2598530d1fd04cebc02cf Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Fri, 19 Jan 2024 15:13:24 -0400 Subject: [PATCH 10/11] Add missing wizardTemplateUuid --- resources/js/templates/assets.js | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/js/templates/assets.js b/resources/js/templates/assets.js index e0dabdc12d..bc695cb314 100644 --- a/resources/js/templates/assets.js +++ b/resources/js/templates/assets.js @@ -12,6 +12,7 @@ new Vue({ responseId: null, request: {}, redirectTo: null, + wizardTemplateUuid: null, }; }, mounted() { From f4ed655abdf50c893c6709a458cb7a2f50a20f99 Mon Sep 17 00:00:00 2001 From: Roly Gutierrez Date: Fri, 19 Jan 2024 16:03:47 -0400 Subject: [PATCH 11/11] FOUR-13327 Time cannot be selected in calendar in columns with datetime options --- .../PMColumnFilterOpDatetime.vue | 63 +++++++++++++------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/resources/js/components/PMColumnFilterPopover/PMColumnFilterOpDatetime.vue b/resources/js/components/PMColumnFilterPopover/PMColumnFilterOpDatetime.vue index 1a3d8b9196..feb2ff3c30 100644 --- a/resources/js/components/PMColumnFilterPopover/PMColumnFilterOpDatetime.vue +++ b/resources/js/components/PMColumnFilterPopover/PMColumnFilterOpDatetime.vue @@ -7,7 +7,7 @@ readonly size="sm"> - + +
@@ -27,44 +36,62 @@ ], data() { return { - input: "" + input: "", + selectedDate: "", + selectedTime: "" }; }, watch: { value: { handler(newValue) { this.input = newValue; - this.dateToDatetime(); }, immediate: true }, input() { this.emitInput(); + }, + selectedDate() { + this.setInput(); + }, + selectedTime() { + this.setInput(); } }, mounted() { - if (this.input === "") { - this.input = this.currentDate(); - } + this.selectedDate = this.getCurrentDate(this.input); + this.selectedTime = this.getCurrentTime(this.input); }, methods: { emitInput() { - this.dateToDatetime(); this.$emit("input", this.input); }, - dateToDatetime() { - if (this.input && this.input !== "" && !/\d{2}:\d{2}:\d{2}/.test(this.input)) { - this.input = this.input + " 00:00:00"; - } + setInput() { + this.input = this.selectedDate + " " + this.selectedTime; }, currentDate() { let date = new Date(); - let year = date.getFullYear(); - let month = date.getMonth() + 1; - let day = date.getDate(); - month = month < 10 ? "0" + month : month; - day = day < 10 ? "0" + day : day; - return year + "-" + month + "-" + day; + return date.toISOString().split("T")[0]; + }, + isDatetime(string) { + const date = new Date(string); + return !isNaN(date.getTime()) && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(string); + }, + getCurrentDate(newValue) { + if (this.isDatetime(newValue)) { + let s = newValue.trim().split(" "); + return s[0]; + } else { + return this.currentDate(); + } + }, + getCurrentTime(newValue) { + if (this.isDatetime(newValue)) { + let s = newValue.trim().split(" "); + return s.length > 1 ? s[1] : "00:00:00"; + } else { + return "00:00:00"; + } } } }; @@ -87,4 +114,4 @@ border-top-right-radius: 0px; border-bottom-right-radius: 0px; } - + \ No newline at end of file