From 54f54fe938e80418a82bb4731d40303432ea4ae0 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 09:35:34 -0500 Subject: [PATCH 01/56] Register survey field blocks. --- .../Blocks/CheckboxSurveyFieldBlock.php | 47 ++++++++++++ .../Filament/Blocks/RadioSurveyFieldBlock.php | 47 ++++++++++++ .../Blocks/SelectSurveyFieldBlock.php | 47 ++++++++++++ .../Blocks/SurveyFieldBlockRegistry.php | 72 +++++++++++++++++++ .../Blocks/TextAreaSurveyFieldBlock.php | 47 ++++++++++++ .../Blocks/TextInputSurveyFieldBlock.php | 47 ++++++++++++ .../Concerns/HasSharedFormConfiguration.php | 4 +- 7 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php create mode 100644 app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php create mode 100644 app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php create mode 100644 app-modules/survey/src/Filament/Blocks/SurveyFieldBlockRegistry.php create mode 100644 app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php create mode 100644 app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php diff --git a/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php new file mode 100644 index 0000000000..7e8671763e --- /dev/null +++ b/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php @@ -0,0 +1,47 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Filament\Blocks; + +use AdvisingApp\Form\Filament\Blocks\CheckboxFormFieldBlock; + +class CheckboxSurveyFieldBlock extends CheckboxFormFieldBlock +{ + public static function type(): string + { + return 'multiple_choice'; + } +} diff --git a/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php new file mode 100644 index 0000000000..c7df3e74e7 --- /dev/null +++ b/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php @@ -0,0 +1,47 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Filament\Blocks; + +use AdvisingApp\Form\Filament\Blocks\RadioFormFieldBlock; + +class RadioSurveyFieldBlock extends RadioFormFieldBlock +{ + public static function type(): string + { + return 'choice_(radio)'; + } +} diff --git a/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php new file mode 100644 index 0000000000..1f6152f801 --- /dev/null +++ b/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php @@ -0,0 +1,47 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Filament\Blocks; + +use AdvisingApp\Form\Filament\Blocks\SelectFormFieldBlock; + +class SelectSurveyFieldBlock extends SelectFormFieldBlock +{ + public static function type(): string + { + return 'choice_(dropdown)'; + } +} diff --git a/app-modules/survey/src/Filament/Blocks/SurveyFieldBlockRegistry.php b/app-modules/survey/src/Filament/Blocks/SurveyFieldBlockRegistry.php new file mode 100644 index 0000000000..2b37c5e8ff --- /dev/null +++ b/app-modules/survey/src/Filament/Blocks/SurveyFieldBlockRegistry.php @@ -0,0 +1,72 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Filament\Blocks; + +use AdvisingApp\Form\Filament\Blocks\EmailFormFieldBlock; +use AdvisingApp\Form\Filament\Blocks\NumberFormFieldBlock; +use AdvisingApp\Form\Filament\Blocks\EducatableEmailFormFieldBlock; + +class SurveyFieldBlockRegistry +{ + /** + * @return array> + */ + public static function get(): array + { + return [ + EducatableEmailFormFieldBlock::class, + TextInputSurveyFieldBlock::class, + TextAreaSurveyFieldBlock::class, + SelectSurveyFieldBlock::class, + RadioSurveyFieldBlock::class, + CheckboxSurveyFieldBlock::class, + EmailFormFieldBlock::class, + NumberFormFieldBlock::class, + ]; + } + + /** + * @return array> + */ + public static function keyByType(): array + { + /** @var FormFieldBlock $block */ + return collect(static::get()) + ->mapWithKeys(fn (string $block): array => [$block::type() => $block]) + ->all(); + } +} diff --git a/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php new file mode 100644 index 0000000000..b6a38e8a03 --- /dev/null +++ b/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php @@ -0,0 +1,47 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Filament\Blocks; + +use AdvisingApp\Form\Filament\Blocks\TextAreaFormFieldBlock; + +class TextAreaSurveyFieldBlock extends TextAreaFormFieldBlock +{ + public static function type(): string + { + return 'question_(multi-line)'; + } +} diff --git a/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php new file mode 100644 index 0000000000..17e0628bfc --- /dev/null +++ b/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php @@ -0,0 +1,47 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Filament\Blocks; + +use AdvisingApp\Form\Filament\Blocks\TextInputFormFieldBlock; + +class TextInputSurveyFieldBlock extends TextInputFormFieldBlock +{ + public static function type(): string + { + return 'question_(single_line)'; + } +} diff --git a/app-modules/survey/src/Filament/Resources/SurveyResource/Pages/Concerns/HasSharedFormConfiguration.php b/app-modules/survey/src/Filament/Resources/SurveyResource/Pages/Concerns/HasSharedFormConfiguration.php index 8999527271..332948559d 100644 --- a/app-modules/survey/src/Filament/Resources/SurveyResource/Pages/Concerns/HasSharedFormConfiguration.php +++ b/app-modules/survey/src/Filament/Resources/SurveyResource/Pages/Concerns/HasSharedFormConfiguration.php @@ -53,8 +53,8 @@ use AdvisingApp\Survey\Models\SurveyStep; use AdvisingApp\Survey\Models\SurveyField; use FilamentTiptapEditor\Enums\TiptapOutput; -use AdvisingApp\Form\Filament\Blocks\FormFieldBlockRegistry; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; +use AdvisingApp\Survey\Filament\Blocks\SurveyFieldBlockRegistry; use AdvisingApp\IntegrationGoogleRecaptcha\Settings\GoogleRecaptchaSettings; trait HasSharedFormConfiguration @@ -146,7 +146,7 @@ public function fieldBuilder(): TiptapEditor { return TiptapEditor::make('content') ->output(TiptapOutput::Json) - ->blocks(FormFieldBlockRegistry::get()) + ->blocks(SurveyFieldBlockRegistry::get()) ->tools(['bold', 'italic', 'small', '|', 'heading', 'bullet-list', 'ordered-list', 'hr', '|', 'link', 'grid', 'blocks']) ->placeholder('Drag blocks here to build your survey') ->hiddenLabel() From 4129bad99a8560d5874ca4fa928fc22d9b75bb5e Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 09:57:46 -0500 Subject: [PATCH 02/56] Update field labels. --- .../survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php | 4 ++-- .../survey/src/Filament/Blocks/RadioSurveyFieldBlock.php | 4 ++-- .../survey/src/Filament/Blocks/SelectSurveyFieldBlock.php | 4 ++-- .../survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php | 4 ++-- .../survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php index 7e8671763e..6b5e23ae58 100644 --- a/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php +++ b/app-modules/survey/src/Filament/Blocks/CheckboxSurveyFieldBlock.php @@ -40,8 +40,8 @@ class CheckboxSurveyFieldBlock extends CheckboxFormFieldBlock { - public static function type(): string + public function getLabel(): string { - return 'multiple_choice'; + return 'Multiple Choice'; } } diff --git a/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php index c7df3e74e7..3b92ba8995 100644 --- a/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php +++ b/app-modules/survey/src/Filament/Blocks/RadioSurveyFieldBlock.php @@ -40,8 +40,8 @@ class RadioSurveyFieldBlock extends RadioFormFieldBlock { - public static function type(): string + public function getLabel(): string { - return 'choice_(radio)'; + return 'Choice (Radio)'; } } diff --git a/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php index 1f6152f801..b700e2eb82 100644 --- a/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php +++ b/app-modules/survey/src/Filament/Blocks/SelectSurveyFieldBlock.php @@ -40,8 +40,8 @@ class SelectSurveyFieldBlock extends SelectFormFieldBlock { - public static function type(): string + public function getLabel(): string { - return 'choice_(dropdown)'; + return 'Choice (Dropdown)'; } } diff --git a/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php index b6a38e8a03..b713bd9a90 100644 --- a/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php +++ b/app-modules/survey/src/Filament/Blocks/TextAreaSurveyFieldBlock.php @@ -40,8 +40,8 @@ class TextAreaSurveyFieldBlock extends TextAreaFormFieldBlock { - public static function type(): string + public function getLabel(): string { - return 'question_(multi-line)'; + return 'Question (Multi-Line)'; } } diff --git a/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php b/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php index 17e0628bfc..d414fb092e 100644 --- a/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php +++ b/app-modules/survey/src/Filament/Blocks/TextInputSurveyFieldBlock.php @@ -40,8 +40,8 @@ class TextInputSurveyFieldBlock extends TextInputFormFieldBlock { - public static function type(): string + public function getLabel(): string { - return 'question_(single_line)'; + return 'Question (Single Line)'; } } From d06233bcf17b4634abadf4a9e421c80fe482a555 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 13:56:54 -0500 Subject: [PATCH 03/56] Setup the separate column licenses Signed-off-by: Kevin Ullyott --- .../LicenseManagement/LicenseLimitsData.php | 5 +++-- app/Filament/Pages/ManageLicenseSettings.php | 12 ++++++++---- .../2023_11_29_192230_create_license_settings.php | 5 +++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/DataTransferObjects/LicenseManagement/LicenseLimitsData.php b/app/DataTransferObjects/LicenseManagement/LicenseLimitsData.php index 21d04a3972..884e07af48 100644 --- a/app/DataTransferObjects/LicenseManagement/LicenseLimitsData.php +++ b/app/DataTransferObjects/LicenseManagement/LicenseLimitsData.php @@ -44,8 +44,9 @@ class LicenseLimitsData extends Data { public function __construct( - public int $crmSeats, - public int $analyticsSeats, + public int $conversationalAiSeats, + public int $retentionCrmSeats, + public int $recruitmentCrmSeats, public int $emails, public int $sms, public string $resetDate, diff --git a/app/Filament/Pages/ManageLicenseSettings.php b/app/Filament/Pages/ManageLicenseSettings.php index 60c226c862..b6c94c6005 100644 --- a/app/Filament/Pages/ManageLicenseSettings.php +++ b/app/Filament/Pages/ManageLicenseSettings.php @@ -96,12 +96,16 @@ public function form(Form $form): Form ->columns() ->schema( [ - TextInput::make('data.limits.crmSeats') - ->label('CRM Seats') + TextInput::make('data.limits.conversationalAiSeats') + ->label('Artificial Intelligence Seats') ->numeric() ->required(), - TextInput::make('data.limits.analyticsSeats') - ->label('Analytics Seats') + TextInput::make('data.limits.retentionCrmSeats') + ->label('Student Success / Retention Seats') + ->numeric() + ->required(), + TextInput::make('data.limits.recruitmentCrmSeats') + ->label('Recruitment CRM Seats') ->numeric() ->required(), TextInput::make('data.limits.emails') diff --git a/database/settings/2023_11_29_192230_create_license_settings.php b/database/settings/2023_11_29_192230_create_license_settings.php index 7f487669cc..cfb3e6bbb4 100644 --- a/database/settings/2023_11_29_192230_create_license_settings.php +++ b/database/settings/2023_11_29_192230_create_license_settings.php @@ -55,8 +55,9 @@ public function up(): void 'end_date' => now()->addYear(), ], 'limits' => [ - 'crm_seats' => 30, - 'analytics_seats' => 15, + 'conversational_ai_seats' => 50, + 'retention_crm_seats' => 25, + 'recruitment_crm_seats' => 10, 'emails' => 1000, 'sms' => 1000, 'reset_date' => now()->format('m-d'), From ab3e3f6179f76469acf123a84617c35fb7565687 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 16:31:00 -0500 Subject: [PATCH 04/56] Update LicenseSettings with addon changes Signed-off-by: Kevin Ullyott --- .../LicenseManagement/LicenseAddonsData.php | 10 +++++----- app/Filament/Pages/ManageLicenseSettings.php | 20 +++++++++---------- ...3_11_29_192230_create_license_settings.php | 10 +++++----- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/DataTransferObjects/LicenseManagement/LicenseAddonsData.php b/app/DataTransferObjects/LicenseManagement/LicenseAddonsData.php index 4f131c4bdf..add8d67d58 100644 --- a/app/DataTransferObjects/LicenseManagement/LicenseAddonsData.php +++ b/app/DataTransferObjects/LicenseManagement/LicenseAddonsData.php @@ -44,13 +44,13 @@ class LicenseAddonsData extends Data { public function __construct( + public bool $onlineForms, + public bool $onlineSurveys, public bool $onlineAdmissions, - public bool $realtimeChat, - public bool $dynamicForms, - public bool $conductSurveys, - public bool $personalAssistant, public bool $serviceManagement, public bool $knowledgeManagement, - public bool $studentAndProspectPortal, + public bool $eventManagement, + public bool $realtimeChat, + public bool $mobileApps, ) {} } diff --git a/app/Filament/Pages/ManageLicenseSettings.php b/app/Filament/Pages/ManageLicenseSettings.php index b6c94c6005..60ac1625a5 100644 --- a/app/Filament/Pages/ManageLicenseSettings.php +++ b/app/Filament/Pages/ManageLicenseSettings.php @@ -125,22 +125,22 @@ public function form(Form $form): Form ->columns() ->schema( [ + Toggle::make('data.addons.onlineForms') + ->label('Online Forms'), + Toggle::make('data.addons.onlineSurveys') + ->label('Online Surveys'), Toggle::make('data.addons.onlineAdmissions') ->label('Online Admissions'), - Toggle::make('data.addons.realtimeChat') - ->label('Realtime Chat'), - Toggle::make('data.addons.dynamicForms') - ->label('Dynamic Forms'), - Toggle::make('data.addons.conductSurveys') - ->label('Conduct Surveys'), - Toggle::make('data.addons.personalAssistant') - ->label('Personal Assistant'), Toggle::make('data.addons.serviceManagement') ->label('Service Management'), Toggle::make('data.addons.knowledgeManagement') ->label('Knowledge Management'), - Toggle::make('data.addons.studentAndProspectPortal') - ->label('Student and Prospect Portal'), + Toggle::make('data.addons.eventManagement') + ->label('Event Management'), + Toggle::make('data.addons.realtimeChat') + ->label('Realtime Chat'), + Toggle::make('data.addons.mobileApps') + ->label('Mobile Apps'), ] ), ]); diff --git a/database/settings/2023_11_29_192230_create_license_settings.php b/database/settings/2023_11_29_192230_create_license_settings.php index cfb3e6bbb4..3d3af1ade5 100644 --- a/database/settings/2023_11_29_192230_create_license_settings.php +++ b/database/settings/2023_11_29_192230_create_license_settings.php @@ -63,14 +63,14 @@ public function up(): void 'reset_date' => now()->format('m-d'), ], 'addons' => [ + 'online_forms' => true, + 'online_surveys' => true, 'online_admissions' => true, - 'realtime_chat' => true, - 'dynamic_forms' => true, - 'conduct_surveys' => true, - 'personal_assistant' => true, 'service_management' => true, 'knowledge_management' => true, - 'student_and_prospect_portal' => true, + 'event_management' => true, + 'realtime_chat' => true, + 'mobileApps' => true, ], ] ); From 49384527ff81282422411b1643350d0a10b38938 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 17:00:00 -0500 Subject: [PATCH 05/56] Update and remove old references Signed-off-by: Kevin Ullyott --- .../src/Filament/Pages/ManageAiSettings.php | 9 ++++++--- .../src/Filament/Pages/PersonalAssistant.php | 8 ++++---- .../Policies/AssistantChatMessageLogPolicy.php | 6 ++---- .../Pages/ListConsentAgreements.php | 5 +++-- .../src/Policies/ConsentAgreementPolicy.php | 6 ++---- app-modules/form/src/Policies/FormPolicy.php | 2 +- .../src/Filament/Pages/ManagePortalSettings.php | 4 ++-- .../Middleware/EnsureSurveysFeatureIsActive.php | 2 +- app/Enums/Feature.php | 15 +++++++-------- .../Resources/UserResource/Pages/ListUsers.php | 13 ++++++------- app/Policies/UserPolicy.php | 10 ---------- 11 files changed, 34 insertions(+), 46 deletions(-) diff --git a/app-modules/assistant/src/Filament/Pages/ManageAiSettings.php b/app-modules/assistant/src/Filament/Pages/ManageAiSettings.php index f2b7567936..5297dc5be9 100644 --- a/app-modules/assistant/src/Filament/Pages/ManageAiSettings.php +++ b/app-modules/assistant/src/Filament/Pages/ManageAiSettings.php @@ -37,7 +37,6 @@ namespace AdvisingApp\Assistant\Filament\Pages; use App\Models\User; -use App\Enums\Feature; use Filament\Forms\Form; use Filament\Pages\SettingsPage; use Filament\Forms\Components\Textarea; @@ -58,7 +57,9 @@ public static function shouldRegisterNavigation(): bool /** @var User $user */ $user = auth()->user(); - return $user->can([Feature::PersonalAssistant->getGateName(), 'assistant.access_ai_settings']); + // TODO: Feature/License Gate | if has AI License + + return $user->can(['assistant.access_ai_settings']); } public function mount(): void @@ -66,7 +67,9 @@ public function mount(): void /** @var User $user */ $user = auth()->user(); - abort_unless($user->can([Feature::PersonalAssistant->getGateName(), 'assistant.access_ai_settings']), 403); + // TODO: Feature/License Gate | if has AI License + + abort_unless($user->can(['assistant.access_ai_settings']), 403); parent::mount(); } diff --git a/app-modules/assistant/src/Filament/Pages/PersonalAssistant.php b/app-modules/assistant/src/Filament/Pages/PersonalAssistant.php index 1683ec61f8..286e93fd51 100644 --- a/app-modules/assistant/src/Filament/Pages/PersonalAssistant.php +++ b/app-modules/assistant/src/Filament/Pages/PersonalAssistant.php @@ -37,7 +37,6 @@ namespace AdvisingApp\Assistant\Filament\Pages; use App\Models\User; -use App\Enums\Feature; use Filament\Forms\Get; use Filament\Pages\Page; use Livewire\Attributes\On; @@ -49,7 +48,6 @@ use Filament\Actions\StaticAction; use Illuminate\Support\Collection; use Filament\Forms\Components\Radio; -use Illuminate\Support\Facades\Gate; use Filament\Forms\Components\Select; use Filament\Support\Enums\Alignment; use Filament\Support\Enums\ActionSize; @@ -110,12 +108,14 @@ public static function shouldRegisterNavigation(): bool /** @var User $user */ $user = auth()->user(); - return Gate::check(Feature::PersonalAssistant->getGateName()) && $user->can('assistant.access'); + // TODO: Feature/License Gate | if has AI License + + return $user->can('assistant.access'); } public function mount(): void { - $this->authorize(Feature::PersonalAssistant->getGateName()); + // TODO: Feature/License Gate | if has AI License $this->authorize('assistant.access'); $this->consentAgreement = ConsentAgreement::where('type', ConsentAgreementType::AzureOpenAI)->first(); diff --git a/app-modules/assistant/src/Policies/AssistantChatMessageLogPolicy.php b/app-modules/assistant/src/Policies/AssistantChatMessageLogPolicy.php index 5addc25240..f0489b5ea9 100644 --- a/app-modules/assistant/src/Policies/AssistantChatMessageLogPolicy.php +++ b/app-modules/assistant/src/Policies/AssistantChatMessageLogPolicy.php @@ -36,7 +36,6 @@ namespace AdvisingApp\Assistant\Policies; -use App\Enums\Feature; use App\Models\Authenticatable; use Illuminate\Auth\Access\Response; use App\Concerns\FeatureAccessEnforcedPolicyBefore; @@ -90,8 +89,7 @@ public function forceDelete(Authenticatable $authenticatable, AssistantChatMessa protected function requiredFeatures(): array { - return [ - Feature::PersonalAssistant, - ]; + // TODO: Feature/License Gate | if has AI License + return []; } } diff --git a/app-modules/consent/src/Filament/Resources/ConsentAgreementResource/Pages/ListConsentAgreements.php b/app-modules/consent/src/Filament/Resources/ConsentAgreementResource/Pages/ListConsentAgreements.php index 60a743fc28..93bc6bc87c 100644 --- a/app-modules/consent/src/Filament/Resources/ConsentAgreementResource/Pages/ListConsentAgreements.php +++ b/app-modules/consent/src/Filament/Resources/ConsentAgreementResource/Pages/ListConsentAgreements.php @@ -37,7 +37,6 @@ namespace AdvisingApp\Consent\Filament\Resources\ConsentAgreementResource\Pages; use App\Models\User; -use App\Enums\Feature; use Filament\Forms\Form; use Filament\Tables\Table; use App\Filament\Columns\IdColumn; @@ -72,7 +71,9 @@ public static function shouldRegisterNavigation(array $parameters = []): bool /** @var User $user */ $user = auth()->user(); - return $user->can([Feature::PersonalAssistant->getGateName(), 'consent_agreement.view-any', 'consent_agreement.*.view', 'consent_agreement.*.update']); + // TODO: Feature/License Gate | if has AI License, may need to prevent mount as well + + return $user->can(['consent_agreement.view-any', 'consent_agreement.*.view', 'consent_agreement.*.update']); } public function form(Form $form): Form diff --git a/app-modules/consent/src/Policies/ConsentAgreementPolicy.php b/app-modules/consent/src/Policies/ConsentAgreementPolicy.php index c1fab30e1c..1f8a71b82f 100644 --- a/app-modules/consent/src/Policies/ConsentAgreementPolicy.php +++ b/app-modules/consent/src/Policies/ConsentAgreementPolicy.php @@ -36,7 +36,6 @@ namespace AdvisingApp\Consent\Policies; -use App\Enums\Feature; use App\Models\Authenticatable; use Illuminate\Auth\Access\Response; use AdvisingApp\Consent\Models\ConsentAgreement; @@ -93,8 +92,7 @@ public function forceDelete(Authenticatable $authenticatable, ConsentAgreement $ protected function requiredFeatures(): array { - return [ - Feature::PersonalAssistant, - ]; + // TODO: Feature/License Gate | if has AI License + return []; } } diff --git a/app-modules/form/src/Policies/FormPolicy.php b/app-modules/form/src/Policies/FormPolicy.php index d6d72f6300..14c33e8645 100644 --- a/app-modules/form/src/Policies/FormPolicy.php +++ b/app-modules/form/src/Policies/FormPolicy.php @@ -105,6 +105,6 @@ public function forceDelete(Authenticatable $authenticatable, Form $form): Respo protected function requiredFeatures(): array { - return [Feature::DynamicForms]; + return [Feature::OnlineForms]; } } diff --git a/app-modules/portal/src/Filament/Pages/ManagePortalSettings.php b/app-modules/portal/src/Filament/Pages/ManagePortalSettings.php index 3b49e86f09..ae234b0eab 100644 --- a/app-modules/portal/src/Filament/Pages/ManagePortalSettings.php +++ b/app-modules/portal/src/Filament/Pages/ManagePortalSettings.php @@ -135,12 +135,12 @@ public function form(Form $form): Form ->label('Files and Documents'), Toggle::make('has_forms') ->label('Forms') - ->disabled(! Gate::check(Feature::DynamicForms->getGateName())) + ->disabled(! Gate::check(Feature::OnlineForms->getGateName())) ->hintIcon(fn (Toggle $component) => $component->isDisabled() ? 'heroicon-m-lock-closed' : null) ->hintIconTooltip('Forms are not a part of your current subscription.'), Toggle::make('has_surveys') ->label('Surveys') - ->disabled(! Gate::check(Feature::ConductSurveys->getGateName())) + ->disabled(! Gate::check(Feature::OnlineSurveys->getGateName())) ->hintIcon(fn (Toggle $component) => $component->isDisabled() ? 'heroicon-m-lock-closed' : null) ->hintIconTooltip('Surveys are not a part of your current subscription.'), ]) diff --git a/app-modules/survey/src/Http/Middleware/EnsureSurveysFeatureIsActive.php b/app-modules/survey/src/Http/Middleware/EnsureSurveysFeatureIsActive.php index 2c0d37c894..9c211af70a 100644 --- a/app-modules/survey/src/Http/Middleware/EnsureSurveysFeatureIsActive.php +++ b/app-modules/survey/src/Http/Middleware/EnsureSurveysFeatureIsActive.php @@ -45,7 +45,7 @@ class EnsureSurveysFeatureIsActive { public function handle(Request $request, Closure $next): Response { - if (! app(LicenseSettings::class)->data->addons->conductSurveys) { + if (! app(LicenseSettings::class)->data->addons->onlineSurveys) { return response()->json(['error' => 'Surveys is not enabled.'], 403); } diff --git a/app/Enums/Feature.php b/app/Enums/Feature.php index 188146291c..a7e8914c0a 100644 --- a/app/Enums/Feature.php +++ b/app/Enums/Feature.php @@ -42,21 +42,20 @@ enum Feature: string { - case OnlineAdmissions = 'online-admissions'; - - case RealtimeChat = 'realtime-chat'; - - case DynamicForms = 'dynamic-forms'; + case OnlineForms = 'online-forms'; - case ConductSurveys = 'conduct-surveys'; + case OnlineSurveys = 'online-surveys'; - case PersonalAssistant = 'personal-assistant'; + case OnlineAdmissions = 'online-admissions'; case ServiceManagement = 'service-management'; case KnowledgeManagement = 'knowledge-management'; - case StudentAndProspectPortal = 'student-and-prospect-portal'; + case EventManagement = 'event-management'; + case RealtimeChat = 'realtime-chat'; + + case MobileApps = 'mobile-apps'; public function generateGate(): void { diff --git a/app/Filament/Resources/UserResource/Pages/ListUsers.php b/app/Filament/Resources/UserResource/Pages/ListUsers.php index 287c793daa..2ec58227e3 100644 --- a/app/Filament/Resources/UserResource/Pages/ListUsers.php +++ b/app/Filament/Resources/UserResource/Pages/ListUsers.php @@ -36,10 +36,7 @@ namespace App\Filament\Resources\UserResource\Pages; -use App\Models\User; -use App\Settings\LicenseSettings; use Filament\Actions\CreateAction; -use Illuminate\Support\HtmlString; use App\Filament\Resources\UserResource; use Filament\Resources\Pages\ListRecords; use Illuminate\Contracts\Support\Htmlable; @@ -50,10 +47,12 @@ class ListUsers extends ListRecords public function getSubheading(): string | Htmlable | null { - return new HtmlString(view('crm-seats', [ - 'count' => User::count(), - 'max' => app(LicenseSettings::class)->data->limits->crmSeats, - ])->render()); + // TODO: Either remove or change to show all possible seats + + //return new HtmlString(view('crm-seats', [ + // 'count' => User::count(), + // 'max' => app(LicenseSettings::class)->data->limits->crmSeats, + //])->render()); } protected function getHeaderActions(): array diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php index 120acf24fc..93eb31eb33 100644 --- a/app/Policies/UserPolicy.php +++ b/app/Policies/UserPolicy.php @@ -38,9 +38,7 @@ use App\Models\User; use App\Models\Authenticatable; -use App\Settings\LicenseSettings; use Illuminate\Auth\Access\Response; -use App\Support\FeatureAccessResponse; class UserPolicy { @@ -62,10 +60,6 @@ public function view(Authenticatable $authenticatable, User $model): Response public function create(Authenticatable $authenticatable): Response { - if (User::count() >= app(LicenseSettings::class)->data->limits->crmSeats) { - return FeatureAccessResponse::deny('You have reached the maximum number of users allowed by your license.'); - } - return $authenticatable->canOrElse( abilities: 'user.create', denyResponse: 'You do not have permission to create users.' @@ -90,10 +84,6 @@ public function delete(Authenticatable $authenticatable, User $model): Response public function restore(Authenticatable $authenticatable, User $model): Response { - if (User::count() >= app(LicenseSettings::class)->data->limits->crmSeats) { - return FeatureAccessResponse::deny('You have reached the maximum number of users allowed by your license.'); - } - return $authenticatable->canOrElse( abilities: ['user.*.restore', "user.{$model->id}.restore"], denyResponse: 'You do not have permission to restore this user.' From f218ca324edd79854dd898a3bc0f61b4a3e15697 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 17:11:56 -0500 Subject: [PATCH 06/56] Fix bug with ListUsers header Signed-off-by: Kevin Ullyott --- app/Filament/Resources/UserResource/Pages/ListUsers.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Filament/Resources/UserResource/Pages/ListUsers.php b/app/Filament/Resources/UserResource/Pages/ListUsers.php index 2ec58227e3..3edd59677c 100644 --- a/app/Filament/Resources/UserResource/Pages/ListUsers.php +++ b/app/Filament/Resources/UserResource/Pages/ListUsers.php @@ -53,6 +53,8 @@ public function getSubheading(): string | Htmlable | null // 'count' => User::count(), // 'max' => app(LicenseSettings::class)->data->limits->crmSeats, //])->render()); + + return null; } protected function getHeaderActions(): array From 969732a77fc25fd1da8c087e5fd7c7210002bdda Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 18:52:21 -0500 Subject: [PATCH 07/56] Create a license management processes Signed-off-by: Kevin Ullyott --- .../config/roles/web/license_management.php | 43 ++++++++++++++ ...024_01_02_225406_create_licenses_table.php | 20 +++++++ .../authorization/src/Enums/LicenseType.php | 40 +++++++++++++ .../authorization/src/Models/License.php | 24 ++++++++ .../src/Rules/LicenseTypeUsageRule.php | 19 ++++++ app/Filament/Resources/UserResource.php | 2 + .../LicensesRelationManager.php | 59 +++++++++++++++++++ app/Models/User.php | 6 ++ 8 files changed, 213 insertions(+) create mode 100644 app-modules/authorization/config/roles/web/license_management.php create mode 100644 app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php create mode 100644 app-modules/authorization/src/Enums/LicenseType.php create mode 100644 app-modules/authorization/src/Models/License.php create mode 100644 app-modules/authorization/src/Rules/LicenseTypeUsageRule.php create mode 100644 app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php diff --git a/app-modules/authorization/config/roles/web/license_management.php b/app-modules/authorization/config/roles/web/license_management.php new file mode 100644 index 0000000000..ac07305bb6 --- /dev/null +++ b/app-modules/authorization/config/roles/web/license_management.php @@ -0,0 +1,43 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +return [ + 'model' => [ + 'license' => [ + '*', + ], + ], +]; diff --git a/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php b/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php new file mode 100644 index 0000000000..475a106a2a --- /dev/null +++ b/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php @@ -0,0 +1,20 @@ +uuid('id')->primary(); + $table->foreignUuid('user_id')->constrained('users')->cascadeOnDelete(); + $table->string('type'); + $table->timestamps(); + $table->softDeletes(); + + $table->unique(['user_id', 'type']); + }); + } +}; diff --git a/app-modules/authorization/src/Enums/LicenseType.php b/app-modules/authorization/src/Enums/LicenseType.php new file mode 100644 index 0000000000..b8d00a8293 --- /dev/null +++ b/app-modules/authorization/src/Enums/LicenseType.php @@ -0,0 +1,40 @@ + 'Conversational AI', + LicenseType::RetentionCrm => 'Retention CRM', + LicenseType::RecruitmentCrm => 'Recruitment CRM', + }; + } + + public function hasAvailableLicenses(): bool + { + $totalLicensesInUse = License::query()->where('type', $this)->count(); + + $licenseSettings = app(LicenseSettings::class); + + $licenseLimit = match ($this) { + LicenseType::ConversationalAi => $licenseSettings->data->limits->conversationalAiSeats, + LicenseType::RetentionCrm => $licenseSettings->data->limits->retentionCrmSeats, + LicenseType::RecruitmentCrm => $licenseSettings->data->limits->recruitmentCrmSeats, + }; + + return $totalLicensesInUse < $licenseLimit; + } +} diff --git a/app-modules/authorization/src/Models/License.php b/app-modules/authorization/src/Models/License.php new file mode 100644 index 0000000000..2bd1c9e128 --- /dev/null +++ b/app-modules/authorization/src/Models/License.php @@ -0,0 +1,24 @@ + LicenseType::class, + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'user_id'); + } +} diff --git a/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php b/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php new file mode 100644 index 0000000000..9eaf5bb06f --- /dev/null +++ b/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php @@ -0,0 +1,19 @@ +hasAvailableLicenses()) { + $fail("There are no available {$licenseType->getLabel()} licenses."); + } + } +} diff --git a/app/Filament/Resources/UserResource.php b/app/Filament/Resources/UserResource.php index 4ef2fd43ee..e799e88286 100644 --- a/app/Filament/Resources/UserResource.php +++ b/app/Filament/Resources/UserResource.php @@ -55,6 +55,7 @@ use App\Filament\Resources\UserResource\Pages\ListUsers; use App\Filament\Resources\UserResource\Pages\CreateUser; use App\Filament\Resources\UserResource\RelationManagers\RolesRelationManager; +use App\Filament\Resources\UserResource\RelationManagers\LicensesRelationManager; use App\Filament\Resources\UserResource\RelationManagers\RoleGroupsRelationManager; use App\Filament\Resources\UserResource\RelationManagers\PermissionsRelationManager; @@ -128,6 +129,7 @@ public static function getRelations(): array RoleGroupsRelationManager::class, RolesRelationManager::class, PermissionsRelationManager::class, + LicensesRelationManager::class, ]; } diff --git a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php new file mode 100644 index 0000000000..0e83fbc945 --- /dev/null +++ b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php @@ -0,0 +1,59 @@ +schema([ + Select::make('type') + ->options(LicenseType::class) + ->enum(LicenseType::class) + ->rule(Rule::unique('licenses', 'type')->where('user_id', $this->getOwnerRecord()->getKey())) + ->rule(new LicenseTypeUsageRule()) + ->required(), + ]); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('type') + ->columns([ + TextColumn::make('type'), + TextColumn::make('created_at') + ->dateTime(), + ]) + ->headerActions([ + CreateAction::make(), + ]) + ->actions([ + DeleteAction::make(), + ]) + ->bulkActions([ + BulkActionGroup::make([ + DeleteBulkAction::make(), + ]), + ]) + ->emptyStateActions([ + CreateAction::make(), + ]); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 798a326208..d68162d962 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -53,6 +53,7 @@ use Filament\Models\Contracts\FilamentUser; use Spatie\MediaLibrary\InteractsWithMedia; use Illuminate\Database\Eloquent\SoftDeletes; +use AdvisingApp\Authorization\Models\License; use AdvisingApp\MeetingCenter\Models\Calendar; use AdvisingApp\Assistant\Models\AssistantChat; use AdvisingApp\StudentDataModel\Models\Student; @@ -195,6 +196,11 @@ public function caseloads(): HasMany return $this->hasMany(Caseload::class); } + public function licenses(): HasMany + { + return $this->hasMany(License::class, 'user_id'); + } + public function subscriptions(): HasMany { return $this->hasMany(Subscription::class); From 964c8f7c988992e7b5ded5c4d9a9999bbb4e515f Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 19:05:29 -0500 Subject: [PATCH 08/56] Setup rules and auditing Signed-off-by: Kevin Ullyott --- .../2024_01_02_225406_create_licenses_table.php | 7 ++++--- app-modules/authorization/src/Models/License.php | 8 +++++++- .../RelationManagers/LicensesRelationManager.php | 6 +++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php b/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php index 475a106a2a..3dee0c08e4 100644 --- a/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php +++ b/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php @@ -1,8 +1,9 @@ timestamps(); $table->softDeletes(); - $table->unique(['user_id', 'type']); + $table->uniqueIndex(['user_id', 'type'])->where(fn (Builder $condition) => $condition->whereNull('deleted_at')); }); } }; diff --git a/app-modules/authorization/src/Models/License.php b/app-modules/authorization/src/Models/License.php index 2bd1c9e128..6d9872477d 100644 --- a/app-modules/authorization/src/Models/License.php +++ b/app-modules/authorization/src/Models/License.php @@ -4,11 +4,17 @@ use App\Models\User; use App\Models\BaseModel; +use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; use AdvisingApp\Authorization\Enums\LicenseType; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableConcern; -class License extends BaseModel +class License extends BaseModel implements Auditable { + use AuditableConcern; + use SoftDeletes; + protected $fillable = [ 'type', ]; diff --git a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php index 0e83fbc945..d5b64554b1 100644 --- a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php +++ b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php @@ -26,7 +26,11 @@ public function form(Form $form): Form Select::make('type') ->options(LicenseType::class) ->enum(LicenseType::class) - ->rule(Rule::unique('licenses', 'type')->where('user_id', $this->getOwnerRecord()->getKey())) + ->rule( + Rule::unique('licenses', 'type') + ->where('user_id', $this->getOwnerRecord()->getKey()) + ->whereNull('deleted_at'), + ) ->rule(new LicenseTypeUsageRule()) ->required(), ]); From 7492447f3385952b0c842edc6a81ae887c41deb5 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 19:22:19 -0500 Subject: [PATCH 09/56] helpers and disables Signed-off-by: Kevin Ullyott --- _ide_helper_models.php | 290 +++++++++++++++--- .../authorization/src/Models/License.php | 3 + .../src/Observers/LicenseObserver.php | 16 + .../AuthorizationServiceProvider.php | 10 + .../inventory-management/src/Models/Asset.php | 3 + .../src/Models/AssetLocation.php | 3 + .../src/Models/AssetStatus.php | 3 + .../src/Models/AssetType.php | 3 + .../src/Models/MaintenanceActivity.php | 3 + .../src/Models/MaintenanceProvider.php | 3 + .../meeting-center/src/Models/Event.php | 3 + .../LicensesRelationManager.php | 7 + app/Models/User.php | 2 +- 13 files changed, 310 insertions(+), 39 deletions(-) create mode 100644 app-modules/authorization/src/Observers/LicenseObserver.php diff --git a/_ide_helper_models.php b/_ide_helper_models.php index 8414883ba6..450515d50f 100644 --- a/_ide_helper_models.php +++ b/_ide_helper_models.php @@ -1,39 +1,5 @@ - - Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. - - Advising App™ is licensed under the Elastic License 2.0. For more details, - see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. - - Notice: - - - You may not provide the software to third parties as a hosted or managed - service, where the service provides users with access to any substantial set of - the features or functionality of the software. - - You may not move, change, disable, or circumvent the license key functionality - in the software, and you may not remove or obscure any functionality in the - software that is protected by the license key. - - You may not alter, remove, or obscure any licensing, copyright, or other notices - of the licensor in the software. Any use of the licensor’s trademarks is subject - to applicable law. - - Canyon GBS LLC respects the intellectual property rights of others and expects the - same in return. Canyon GBS™ and Advising App™ are registered trademarks of - Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks - vigorously. - - The software solution, including services, infrastructure, and code, is offered as a - Software as a Service (SaaS) by Canyon GBS LLC. - - Use of this software implies agreement to the license terms and conditions as stated - in the Elastic License 2.0. - - For more information or inquiries please visit our website at - https://www.canyongbs.com or contact us via email at legal@canyongbs.com. - - -*/ - // @formatter:off /** * A helper file for your Eloquent Models @@ -330,6 +296,8 @@ class IdeHelperSystemUser {} * @property-read \Illuminate\Database\Eloquent\Collection $events * @property-read int|null $events_count * @property-read mixed $is_admin + * @property-read \Illuminate\Database\Eloquent\Collection $licenses + * @property-read int|null $licenses_count * @property-read \Spatie\MediaLibrary\MediaCollections\Models\Collections\MediaCollection $media * @property-read int|null $media_count * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications @@ -820,6 +788,35 @@ class IdeHelperAssistantChatMessageLog {} class IdeHelperAudit {} } +namespace AdvisingApp\Authorization\Models{ +/** + * AdvisingApp\Authorization\Models\License + * + * @property string $id + * @property string $user_id + * @property \AdvisingApp\Authorization\Enums\LicenseType $type + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property \Illuminate\Support\Carbon|null $deleted_at + * @property-read \App\Models\User $user + * @method static \Illuminate\Database\Eloquent\Builder|License newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|License newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|License onlyTrashed() + * @method static \Illuminate\Database\Eloquent\Builder|License query() + * @method static \Illuminate\Database\Eloquent\Builder|License whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|License whereDeletedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|License whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|License whereType($value) + * @method static \Illuminate\Database\Eloquent\Builder|License whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|License whereUserId($value) + * @method static \Illuminate\Database\Eloquent\Builder|License withTrashed() + * @method static \Illuminate\Database\Eloquent\Builder|License withoutTrashed() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperLicense {} +} + namespace AdvisingApp\Authorization\Models{ /** * AdvisingApp\Authorization\Models\Permission @@ -1011,7 +1008,7 @@ class IdeHelperCampaign {} * @property string $campaign_id * @property \AdvisingApp\Campaign\Enums\CampaignActionType $type * @property array $data - * @property string $execute_at + * @property \Illuminate\Support\Carbon $execute_at * @property string|null $last_execution_attempt_at * @property string|null $last_execution_attempt_error * @property string|null $successfully_executed_at @@ -1311,6 +1308,7 @@ class IdeHelperEmailTemplate {} * @method static \AdvisingApp\Engagement\Database\Factories\EngagementFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|Engagement hasBeenDelivered() * @method static \Illuminate\Database\Eloquent\Builder|Engagement hasNotBeenDelivered() + * @method static \Illuminate\Database\Eloquent\Builder|Engagement isAwaitingDelivery() * @method static \Illuminate\Database\Eloquent\Builder|Engagement isNotPartOfABatch() * @method static \Illuminate\Database\Eloquent\Builder|Engagement isScheduled() * @method static \Illuminate\Database\Eloquent\Builder|Engagement newModelQuery() @@ -1984,6 +1982,189 @@ class IdeHelperInteractionStatus {} class IdeHelperInteractionType {} } +namespace AdvisingApp\InventoryManagement\Models{ +/** + * AdvisingApp\InventoryManagement\Models\Asset + * + * @property string $id + * @property string $serial_number + * @property string $name + * @property string $description + * @property string $type_id + * @property string $status_id + * @property string $location_id + * @property string $purchase_date + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count + * @property-read \AdvisingApp\InventoryManagement\Models\AssetLocation $location + * @property-read \Illuminate\Database\Eloquent\Collection $maintenanceActivities + * @property-read int|null $maintenance_activities_count + * @property-read \AdvisingApp\InventoryManagement\Models\AssetStatus $status + * @property-read \AdvisingApp\InventoryManagement\Models\AssetType $type + * @method static \AdvisingApp\InventoryManagement\Database\Factories\AssetFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|Asset newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Asset newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Asset query() + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereLocationId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset wherePurchaseDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereSerialNumber($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereStatusId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereTypeId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Asset whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperAsset {} +} + +namespace AdvisingApp\InventoryManagement\Models{ +/** + * AdvisingApp\InventoryManagement\Models\AssetLocation + * + * @property string $id + * @property string $name + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $assets + * @property-read int|null $assets_count + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count + * @method static \AdvisingApp\InventoryManagement\Database\Factories\AssetLocationFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation query() + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetLocation whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperAssetLocation {} +} + +namespace AdvisingApp\InventoryManagement\Models{ +/** + * AdvisingApp\InventoryManagement\Models\AssetStatus + * + * @property string $id + * @property string $name + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $assets + * @property-read int|null $assets_count + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count + * @method static \AdvisingApp\InventoryManagement\Database\Factories\AssetStatusFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus query() + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetStatus whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperAssetStatus {} +} + +namespace AdvisingApp\InventoryManagement\Models{ +/** + * AdvisingApp\InventoryManagement\Models\AssetType + * + * @property string $id + * @property string $name + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $assets + * @property-read int|null $assets_count + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count + * @method static \AdvisingApp\InventoryManagement\Database\Factories\AssetTypeFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|AssetType newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|AssetType newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|AssetType query() + * @method static \Illuminate\Database\Eloquent\Builder|AssetType whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetType whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetType whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|AssetType whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperAssetType {} +} + +namespace AdvisingApp\InventoryManagement\Models{ +/** + * AdvisingApp\InventoryManagement\Models\MaintenanceActivity + * + * @property string $id + * @property string $asset_id + * @property string|null $maintenance_provider_id + * @property string $details + * @property \Illuminate\Support\Carbon|null $scheduled_date + * @property \Illuminate\Support\Carbon|null $completed_date + * @property \AdvisingApp\InventoryManagement\Enums\MaintenanceActivityStatus $status + * @property string|null $notes + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \AdvisingApp\InventoryManagement\Models\Asset $asset + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count + * @property-read \AdvisingApp\InventoryManagement\Models\MaintenanceProvider|null $maintenanceProvider + * @method static \AdvisingApp\InventoryManagement\Database\Factories\MaintenanceActivityFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity query() + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereAssetId($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereCompletedDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereDetails($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereMaintenanceProviderId($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereScheduledDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceActivity whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperMaintenanceActivity {} +} + +namespace AdvisingApp\InventoryManagement\Models{ +/** + * AdvisingApp\InventoryManagement\Models\MaintenanceProvider + * + * @property string $id + * @property string $name + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count + * @property-read \Illuminate\Database\Eloquent\Collection $maintenanceActivities + * @property-read int|null $maintenance_activities_count + * @method static \AdvisingApp\InventoryManagement\Database\Factories\MaintenanceProviderFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider query() + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|MaintenanceProvider whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperMaintenanceProvider {} +} + namespace AdvisingApp\KnowledgeBase\Models{ /** * AdvisingApp\KnowledgeBase\Models\KnowledgeBaseCategory @@ -2022,8 +2203,8 @@ class IdeHelperKnowledgeBaseCategory {} * @property string $id * @property string $question * @property bool $public - * @property string|null $solution - * @property string|null $notes + * @property array|null $solution + * @property array|null $notes * @property string|null $quality_id * @property string|null $status_id * @property string|null $category_id @@ -2194,6 +2375,38 @@ class IdeHelperCalendar {} class IdeHelperCalendarEvent {} } +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\Event + * + * @property string $id + * @property string $title + * @property string|null $description + * @property string|null $location + * @property int|null $capacity + * @property \Illuminate\Support\Carbon $starts_at + * @property \Illuminate\Support\Carbon $ends_at + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @method static \AdvisingApp\MeetingCenter\Database\Factories\EventFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|Event newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Event newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Event query() + * @method static \Illuminate\Database\Eloquent\Builder|Event whereCapacity($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereEndsAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereLocation($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereStartsAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereTitle($value) + * @method static \Illuminate\Database\Eloquent\Builder|Event whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEvent {} +} + namespace AdvisingApp\Notification\Models{ /** * AdvisingApp\Notification\Models\OutboundDeliverable @@ -2290,7 +2503,7 @@ class IdeHelperSubscription {} * @property string|null $phone * @property string|null $address * @property string|null $address_2 - * @property string|null $birthdate + * @property \Illuminate\Support\Carbon|null $birthdate * @property string|null $hsgrad * @property string|null $assigned_to_id * @property string|null $created_by_id @@ -2744,6 +2957,7 @@ class IdeHelperProgram {} * AdvisingApp\StudentDataModel\Models\Student * * @property string $display_name + * @property string $mobile * @property-read \Illuminate\Database\Eloquent\Collection $alerts * @property-read int|null $alerts_count * @property-read \Illuminate\Database\Eloquent\Collection $applicationSubmissions diff --git a/app-modules/authorization/src/Models/License.php b/app-modules/authorization/src/Models/License.php index 6d9872477d..209491a7d3 100644 --- a/app-modules/authorization/src/Models/License.php +++ b/app-modules/authorization/src/Models/License.php @@ -10,6 +10,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableConcern; +/** + * @mixin IdeHelperLicense + */ class License extends BaseModel implements Auditable { use AuditableConcern; diff --git a/app-modules/authorization/src/Observers/LicenseObserver.php b/app-modules/authorization/src/Observers/LicenseObserver.php new file mode 100644 index 0000000000..a06f90af0a --- /dev/null +++ b/app-modules/authorization/src/Observers/LicenseObserver.php @@ -0,0 +1,16 @@ +type->hasAvailableLicenses()) { + throw new Exception("There are no available {$license->type->getLabel()} licenses."); + } + } +} diff --git a/app-modules/authorization/src/Providers/AuthorizationServiceProvider.php b/app-modules/authorization/src/Providers/AuthorizationServiceProvider.php index 22a4eba828..ce36123f8b 100644 --- a/app-modules/authorization/src/Providers/AuthorizationServiceProvider.php +++ b/app-modules/authorization/src/Providers/AuthorizationServiceProvider.php @@ -40,6 +40,7 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; use AdvisingApp\Authorization\Models\Role; +use AdvisingApp\Authorization\Models\License; use AdvisingApp\Authorization\Models\RoleGroup; use AdvisingApp\Authorization\Models\Permission; use AdvisingApp\Authorization\AuthorizationPlugin; @@ -48,6 +49,7 @@ use Illuminate\Database\Eloquent\Relations\Relation; use SocialiteProviders\Google\GoogleExtendSocialite; use AdvisingApp\Authorization\AuthorizationRoleRegistry; +use AdvisingApp\Authorization\Observers\LicenseObserver; use AdvisingApp\Authorization\AuthorizationPermissionRegistry; class AuthorizationServiceProvider extends ServiceProvider @@ -73,8 +75,11 @@ public function boot(AuthorizationPermissionRegistry $permissionRegistry, Author 'role' => Role::class, 'permission' => Permission::class, 'role_group' => RoleGroup::class, + 'license' => License::class, ]); + $this->registerObservers(); + $permissionRegistry->registerApiPermissions( module: 'authorization', path: 'permissions/api/custom' @@ -105,4 +110,9 @@ public function boot(AuthorizationPermissionRegistry $permissionRegistry, Author listener: GoogleExtendSocialite::class . '@handle' ); } + + public function registerObservers(): void + { + License::observe(LicenseObserver::class); + } } diff --git a/app-modules/inventory-management/src/Models/Asset.php b/app-modules/inventory-management/src/Models/Asset.php index a2d9dca12d..0c47192b9e 100644 --- a/app-modules/inventory-management/src/Models/Asset.php +++ b/app-modules/inventory-management/src/Models/Asset.php @@ -42,6 +42,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +/** + * @mixin IdeHelperAsset + */ class Asset extends BaseModel implements Auditable { use AuditableTrait; diff --git a/app-modules/inventory-management/src/Models/AssetLocation.php b/app-modules/inventory-management/src/Models/AssetLocation.php index 37c656e292..d310c7f8b9 100644 --- a/app-modules/inventory-management/src/Models/AssetLocation.php +++ b/app-modules/inventory-management/src/Models/AssetLocation.php @@ -41,6 +41,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +/** + * @mixin IdeHelperAssetLocation + */ class AssetLocation extends BaseModel implements Auditable { use AuditableTrait; diff --git a/app-modules/inventory-management/src/Models/AssetStatus.php b/app-modules/inventory-management/src/Models/AssetStatus.php index da1000a351..5214a52f50 100644 --- a/app-modules/inventory-management/src/Models/AssetStatus.php +++ b/app-modules/inventory-management/src/Models/AssetStatus.php @@ -41,6 +41,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +/** + * @mixin IdeHelperAssetStatus + */ class AssetStatus extends BaseModel implements Auditable { use AuditableTrait; diff --git a/app-modules/inventory-management/src/Models/AssetType.php b/app-modules/inventory-management/src/Models/AssetType.php index e00d56af4e..f1a9bde9f0 100644 --- a/app-modules/inventory-management/src/Models/AssetType.php +++ b/app-modules/inventory-management/src/Models/AssetType.php @@ -41,6 +41,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +/** + * @mixin IdeHelperAssetType + */ class AssetType extends BaseModel implements Auditable { use AuditableTrait; diff --git a/app-modules/inventory-management/src/Models/MaintenanceActivity.php b/app-modules/inventory-management/src/Models/MaintenanceActivity.php index 71c75c3ad5..7431ad186f 100644 --- a/app-modules/inventory-management/src/Models/MaintenanceActivity.php +++ b/app-modules/inventory-management/src/Models/MaintenanceActivity.php @@ -42,6 +42,9 @@ use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; use AdvisingApp\InventoryManagement\Enums\MaintenanceActivityStatus; +/** + * @mixin IdeHelperMaintenanceActivity + */ class MaintenanceActivity extends BaseModel implements Auditable { use AuditableTrait; diff --git a/app-modules/inventory-management/src/Models/MaintenanceProvider.php b/app-modules/inventory-management/src/Models/MaintenanceProvider.php index c319b8eec9..79c81e28e8 100644 --- a/app-modules/inventory-management/src/Models/MaintenanceProvider.php +++ b/app-modules/inventory-management/src/Models/MaintenanceProvider.php @@ -41,6 +41,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +/** + * @mixin IdeHelperMaintenanceProvider + */ class MaintenanceProvider extends BaseModel implements Auditable { use AuditableTrait; diff --git a/app-modules/meeting-center/src/Models/Event.php b/app-modules/meeting-center/src/Models/Event.php index 401917e9be..6484c5341e 100644 --- a/app-modules/meeting-center/src/Models/Event.php +++ b/app-modules/meeting-center/src/Models/Event.php @@ -38,6 +38,9 @@ use App\Models\BaseModel; +/** + * @mixin IdeHelperEvent + */ class Event extends BaseModel { protected $fillable = [ diff --git a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php index d5b64554b1..62e5dd8653 100644 --- a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php +++ b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources\UserResource\RelationManagers; +use App\Models\User; use Filament\Forms\Form; use Filament\Tables\Table; use Illuminate\Validation\Rule; @@ -32,6 +33,12 @@ public function form(Form $form): Form ->whereNull('deleted_at'), ) ->rule(new LicenseTypeUsageRule()) + ->disableOptionWhen(function (string $value) { + /** @var User $ownerRecord */ + $ownerRecord = $this->getOwnerRecord(); + + return ! LicenseType::from($value)->hasAvailableLicenses() || $ownerRecord->licenses()->where('type', $value)->exists(); + }) ->required(), ]); } diff --git a/app/Models/User.php b/app/Models/User.php index d68162d962..08cb1dc89b 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -52,8 +52,8 @@ use Lab404\Impersonate\Models\Impersonate; use Filament\Models\Contracts\FilamentUser; use Spatie\MediaLibrary\InteractsWithMedia; -use Illuminate\Database\Eloquent\SoftDeletes; use AdvisingApp\Authorization\Models\License; +use Illuminate\Database\Eloquent\SoftDeletes; use AdvisingApp\MeetingCenter\Models\Calendar; use AdvisingApp\Assistant\Models\AssistantChat; use AdvisingApp\StudentDataModel\Models\Student; From a8f06249160f94a54e76bf205450d9cfaa96b21f Mon Sep 17 00:00:00 2001 From: Orrison Date: Wed, 3 Jan 2024 00:27:06 +0000 Subject: [PATCH 10/56] chore: fix enforcement of copyright on all files --- _ide_helper_models.php | 34 +++++++++++++++++++ ...024_01_02_225406_create_licenses_table.php | 34 +++++++++++++++++++ .../authorization/src/Enums/LicenseType.php | 34 +++++++++++++++++++ .../authorization/src/Models/License.php | 34 +++++++++++++++++++ .../src/Observers/LicenseObserver.php | 34 +++++++++++++++++++ .../src/Rules/LicenseTypeUsageRule.php | 34 +++++++++++++++++++ .../LicensesRelationManager.php | 34 +++++++++++++++++++ 7 files changed, 238 insertions(+) diff --git a/_ide_helper_models.php b/_ide_helper_models.php index 450515d50f..520c0c5be7 100644 --- a/_ide_helper_models.php +++ b/_ide_helper_models.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + // @formatter:off /** * A helper file for your Eloquent Models diff --git a/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php b/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php index 3dee0c08e4..eac079e191 100644 --- a/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php +++ b/app-modules/authorization/database/migrations/2024_01_02_225406_create_licenses_table.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + use Illuminate\Database\Query\Builder; use Illuminate\Database\Migrations\Migration; use Tpetry\PostgresqlEnhanced\Schema\Blueprint; diff --git a/app-modules/authorization/src/Enums/LicenseType.php b/app-modules/authorization/src/Enums/LicenseType.php index b8d00a8293..5e7e9d06db 100644 --- a/app-modules/authorization/src/Enums/LicenseType.php +++ b/app-modules/authorization/src/Enums/LicenseType.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\Authorization\Enums; use App\Settings\LicenseSettings; diff --git a/app-modules/authorization/src/Models/License.php b/app-modules/authorization/src/Models/License.php index 209491a7d3..91dc3f04c9 100644 --- a/app-modules/authorization/src/Models/License.php +++ b/app-modules/authorization/src/Models/License.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\Authorization\Models; use App\Models\User; diff --git a/app-modules/authorization/src/Observers/LicenseObserver.php b/app-modules/authorization/src/Observers/LicenseObserver.php index a06f90af0a..c1280f5f78 100644 --- a/app-modules/authorization/src/Observers/LicenseObserver.php +++ b/app-modules/authorization/src/Observers/LicenseObserver.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\Authorization\Observers; use Exception; diff --git a/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php b/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php index 9eaf5bb06f..16ed3c0982 100644 --- a/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php +++ b/app-modules/authorization/src/Rules/LicenseTypeUsageRule.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\Authorization\Rules; use Closure; diff --git a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php index 62e5dd8653..1487568274 100644 --- a/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php +++ b/app/Filament/Resources/UserResource/RelationManagers/LicensesRelationManager.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace App\Filament\Resources\UserResource\RelationManagers; use App\Models\User; From dd49f2a4ea52995b894342180509aa95e8232ff6 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Thu, 28 Dec 2023 08:32:55 -0500 Subject: [PATCH 11/56] Create AssetExchange model, add soft deletes. --- ..._12_26_181818_create_asset_types_table.php | 1 + ..._26_181828_create_asset_statuses_table.php | 2 + ...26_181837_create_asset_locations_table.php | 1 + .../2023_12_26_181855_create_assets_table.php | 1 + ...502_create_maintenance_providers_table.php | 1 + ...12_create_maintenance_activities_table.php | 1 + ...28_131317_create_asset_exchanges_table.php | 22 +++++++++ .../inventory-management/src/Models/Asset.php | 24 ++++++++-- .../src/Models/AssetExchange.php | 45 +++++++++++++++++++ .../src/Models/AssetLocation.php | 6 ++- .../src/Models/AssetStatus.php | 12 ++++- .../src/Models/AssetType.php | 6 ++- .../src/Models/MaintenanceActivity.php | 8 ++-- .../src/Models/MaintenanceProvider.php | 2 + .../src/Models/ServiceRequestStatus.php | 1 - 15 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php create mode 100644 app-modules/inventory-management/src/Models/AssetExchange.php diff --git a/app-modules/inventory-management/database/migrations/2023_12_26_181818_create_asset_types_table.php b/app-modules/inventory-management/database/migrations/2023_12_26_181818_create_asset_types_table.php index c2d2c62e99..64a6b5b6f8 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_26_181818_create_asset_types_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_26_181818_create_asset_types_table.php @@ -45,6 +45,7 @@ public function up(): void $table->uuid('id')->primary(); $table->string('name'); $table->timestamps(); + $table->softDeletes(); }); } }; diff --git a/app-modules/inventory-management/database/migrations/2023_12_26_181828_create_asset_statuses_table.php b/app-modules/inventory-management/database/migrations/2023_12_26_181828_create_asset_statuses_table.php index c50e496550..01fe18f9cc 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_26_181828_create_asset_statuses_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_26_181828_create_asset_statuses_table.php @@ -43,8 +43,10 @@ public function up(): void { Schema::create('asset_statuses', function (Blueprint $table) { $table->uuid('id')->primary(); + $table->string('classification'); $table->string('name'); $table->timestamps(); + $table->softDeletes(); }); } }; diff --git a/app-modules/inventory-management/database/migrations/2023_12_26_181837_create_asset_locations_table.php b/app-modules/inventory-management/database/migrations/2023_12_26_181837_create_asset_locations_table.php index f3264d6e79..6409f01e97 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_26_181837_create_asset_locations_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_26_181837_create_asset_locations_table.php @@ -45,6 +45,7 @@ public function up(): void $table->uuid('id')->primary(); $table->string('name'); $table->timestamps(); + $table->softDeletes(); }); } }; diff --git a/app-modules/inventory-management/database/migrations/2023_12_26_181855_create_assets_table.php b/app-modules/inventory-management/database/migrations/2023_12_26_181855_create_assets_table.php index 57de8650b8..46ee693db6 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_26_181855_create_assets_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_26_181855_create_assets_table.php @@ -51,6 +51,7 @@ public function up(): void $table->foreignUuid('location_id')->constrained('asset_locations'); $table->timestamp('purchase_date'); $table->timestamps(); + $table->softDeletes(); }); } }; diff --git a/app-modules/inventory-management/database/migrations/2023_12_27_175502_create_maintenance_providers_table.php b/app-modules/inventory-management/database/migrations/2023_12_27_175502_create_maintenance_providers_table.php index c3ca71714d..f12366afe3 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_27_175502_create_maintenance_providers_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_27_175502_create_maintenance_providers_table.php @@ -45,6 +45,7 @@ public function up(): void $table->uuid('id')->primary(); $table->string('name'); $table->timestamps(); + $table->softDeletes(); }); } }; diff --git a/app-modules/inventory-management/database/migrations/2023_12_27_175512_create_maintenance_activities_table.php b/app-modules/inventory-management/database/migrations/2023_12_27_175512_create_maintenance_activities_table.php index 3caa469ecd..b78014de87 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_27_175512_create_maintenance_activities_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_27_175512_create_maintenance_activities_table.php @@ -55,6 +55,7 @@ public function up(): void $table->string('status')->default(MaintenanceActivityStatus::Scheduled); $table->longText('notes')->nullable(); $table->timestamps(); + $table->softDeletes(); }); } }; diff --git a/app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php b/app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php new file mode 100644 index 0000000000..d474c186f1 --- /dev/null +++ b/app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php @@ -0,0 +1,22 @@ +uuid('id')->primary(); + $table->foreignUuid('asset_id')->constrained('assets'); + $table->string('type'); + $table->string('performed_by_type')->nullable(); + $table->string('performed_by_id')->nullable(); + $table->string('for_type'); + $table->string('for_id'); + $table->timestamps(); + $table->softDeletes(); + }); + } +}; diff --git a/app-modules/inventory-management/src/Models/Asset.php b/app-modules/inventory-management/src/Models/Asset.php index 0c47192b9e..02c7dd281f 100644 --- a/app-modules/inventory-management/src/Models/Asset.php +++ b/app-modules/inventory-management/src/Models/Asset.php @@ -36,11 +36,13 @@ namespace AdvisingApp\InventoryManagement\Models; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use AdvisingApp\InventoryManagement\Enums\AssetExchangeType; use App\Models\BaseModel; -use OwenIt\Auditing\Contracts\Auditable; -use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; +use OwenIt\Auditing\Contracts\Auditable; /** * @mixin IdeHelperAsset @@ -48,6 +50,7 @@ class Asset extends BaseModel implements Auditable { use AuditableTrait; + use SoftDeletes; protected $fillable = [ 'description', @@ -78,4 +81,19 @@ public function maintenanceActivities(): HasMany { return $this->hasMany(MaintenanceActivity::class, 'asset_id'); } + + public function exchanges(): HasMany + { + return $this->hasMany(AssetExchange::class, 'asset_id'); + } + + public function checkOuts(): HasMany + { + return $this->exchanges()->where('type', AssetExchangeType::CheckOut); + } + + public function checkIns(): HasMany + { + return $this->exchanges()->where('type', AssetExchangeType::CheckIn); + } } diff --git a/app-modules/inventory-management/src/Models/AssetExchange.php b/app-modules/inventory-management/src/Models/AssetExchange.php new file mode 100644 index 0000000000..41107d7e83 --- /dev/null +++ b/app-modules/inventory-management/src/Models/AssetExchange.php @@ -0,0 +1,45 @@ + AssetExchangeType::class, + ]; + + public function asset(): BelongsTo + { + return $this->belongsTo(Asset::class, 'asset_id'); + } + + public function scopeCheckIn(Builder $query): void + { + $query->where('type', AssetExchangeType::CheckIn); + } + + public function scopeCheckOut(Builder $query): void + { + $query->where('type', AssetExchangeType::CheckOut); + } +} diff --git a/app-modules/inventory-management/src/Models/AssetLocation.php b/app-modules/inventory-management/src/Models/AssetLocation.php index d310c7f8b9..35e1f96256 100644 --- a/app-modules/inventory-management/src/Models/AssetLocation.php +++ b/app-modules/inventory-management/src/Models/AssetLocation.php @@ -36,10 +36,11 @@ namespace AdvisingApp\InventoryManagement\Models; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; use App\Models\BaseModel; -use OwenIt\Auditing\Contracts\Auditable; use Illuminate\Database\Eloquent\Relations\HasMany; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use Illuminate\Database\Eloquent\SoftDeletes; +use OwenIt\Auditing\Contracts\Auditable; /** * @mixin IdeHelperAssetLocation @@ -47,6 +48,7 @@ class AssetLocation extends BaseModel implements Auditable { use AuditableTrait; + use SoftDeletes; protected $fillable = [ 'name', diff --git a/app-modules/inventory-management/src/Models/AssetStatus.php b/app-modules/inventory-management/src/Models/AssetStatus.php index 5214a52f50..ad32d6023a 100644 --- a/app-modules/inventory-management/src/Models/AssetStatus.php +++ b/app-modules/inventory-management/src/Models/AssetStatus.php @@ -36,10 +36,12 @@ namespace AdvisingApp\InventoryManagement\Models; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; use App\Models\BaseModel; -use OwenIt\Auditing\Contracts\Auditable; use Illuminate\Database\Eloquent\Relations\HasMany; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use Illuminate\Database\Eloquent\SoftDeletes; +use OwenIt\Auditing\Contracts\Auditable; /** * @mixin IdeHelperAssetStatus @@ -47,11 +49,17 @@ class AssetStatus extends BaseModel implements Auditable { use AuditableTrait; + use SoftDeletes; protected $fillable = [ + 'classification', 'name', ]; + protected $casts = [ + 'classification' => SystemAssetStatusClassification::class, + ]; + public function assets(): HasMany { return $this->hasMany(Asset::class, 'status_id'); diff --git a/app-modules/inventory-management/src/Models/AssetType.php b/app-modules/inventory-management/src/Models/AssetType.php index f1a9bde9f0..1a492ebdfb 100644 --- a/app-modules/inventory-management/src/Models/AssetType.php +++ b/app-modules/inventory-management/src/Models/AssetType.php @@ -36,10 +36,11 @@ namespace AdvisingApp\InventoryManagement\Models; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; use App\Models\BaseModel; -use OwenIt\Auditing\Contracts\Auditable; use Illuminate\Database\Eloquent\Relations\HasMany; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use Illuminate\Database\Eloquent\SoftDeletes; +use OwenIt\Auditing\Contracts\Auditable; /** * @mixin IdeHelperAssetType @@ -47,6 +48,7 @@ class AssetType extends BaseModel implements Auditable { use AuditableTrait; + use SoftDeletes; protected $fillable = [ 'name', diff --git a/app-modules/inventory-management/src/Models/MaintenanceActivity.php b/app-modules/inventory-management/src/Models/MaintenanceActivity.php index 7431ad186f..6bc1748b66 100644 --- a/app-modules/inventory-management/src/Models/MaintenanceActivity.php +++ b/app-modules/inventory-management/src/Models/MaintenanceActivity.php @@ -36,11 +36,12 @@ namespace AdvisingApp\InventoryManagement\Models; -use App\Models\BaseModel; -use OwenIt\Auditing\Contracts\Auditable; -use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; use AdvisingApp\InventoryManagement\Enums\MaintenanceActivityStatus; +use App\Models\BaseModel; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\SoftDeletes; +use OwenIt\Auditing\Contracts\Auditable; /** * @mixin IdeHelperMaintenanceActivity @@ -48,6 +49,7 @@ class MaintenanceActivity extends BaseModel implements Auditable { use AuditableTrait; + use SoftDeletes; protected $fillable = [ 'asset_id', diff --git a/app-modules/inventory-management/src/Models/MaintenanceProvider.php b/app-modules/inventory-management/src/Models/MaintenanceProvider.php index 79c81e28e8..6acc6b5019 100644 --- a/app-modules/inventory-management/src/Models/MaintenanceProvider.php +++ b/app-modules/inventory-management/src/Models/MaintenanceProvider.php @@ -38,6 +38,7 @@ use App\Models\BaseModel; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\HasMany; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; @@ -47,6 +48,7 @@ class MaintenanceProvider extends BaseModel implements Auditable { use AuditableTrait; + use SoftDeletes; protected $fillable = [ 'name', diff --git a/app-modules/service-management/src/Models/ServiceRequestStatus.php b/app-modules/service-management/src/Models/ServiceRequestStatus.php index 22c8749bc9..40bd3148b5 100644 --- a/app-modules/service-management/src/Models/ServiceRequestStatus.php +++ b/app-modules/service-management/src/Models/ServiceRequestStatus.php @@ -52,7 +52,6 @@ class ServiceRequestStatus extends BaseModel implements Auditable { use SoftDeletes; - use HasUuids; use AuditableTrait; protected $fillable = [ From 77d723bc9704e548def6b64164c17016308f07d6 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Thu, 28 Dec 2023 08:33:16 -0500 Subject: [PATCH 12/56] Asset exchange type and system classification. --- .../src/Enums/AssetExchangeType.php | 50 +++++++++++++++++ .../Enums/SystemAssetStatusClassification.php | 53 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 app-modules/inventory-management/src/Enums/AssetExchangeType.php create mode 100644 app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php diff --git a/app-modules/inventory-management/src/Enums/AssetExchangeType.php b/app-modules/inventory-management/src/Enums/AssetExchangeType.php new file mode 100644 index 0000000000..9af8a53029 --- /dev/null +++ b/app-modules/inventory-management/src/Enums/AssetExchangeType.php @@ -0,0 +1,50 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Enums; + +use Filament\Support\Contracts\HasLabel; + +enum AssetExchangeType: string implements HasLabel +{ + case CheckIn = 'check_in'; + case CheckOut = 'check_out'; + + public function getLabel(): ?string + { + return $this->name; + } +} diff --git a/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php b/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php new file mode 100644 index 0000000000..d1b153e600 --- /dev/null +++ b/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php @@ -0,0 +1,53 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Enums; + +use Filament\Support\Contracts\HasLabel; + +enum SystemAssetStatusClassification: string implements HasLabel +{ + case Available = 'available'; + + case Unavailable = 'unavailable'; + + case Custom = 'custom'; + + public function getLabel(): ?string + { + return $this->name; + } +} From b71c071c787768563c7d44fa31c25b2ea3f07202 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Thu, 28 Dec 2023 08:42:56 -0500 Subject: [PATCH 13/56] Add policies. --- .../src/Policies/AssetExchangePolicy.php | 100 ++++++++++++++++++ .../src/Policies/AssetLocationPolicy.php | 100 ++++++++++++++++++ .../src/Policies/AssetPolicy.php | 100 ++++++++++++++++++ .../src/Policies/AssetStatusPolicy.php | 100 ++++++++++++++++++ .../src/Policies/AssetTypePolicy.php | 100 ++++++++++++++++++ .../Policies/MaintenanceActivityPolicy.php | 100 ++++++++++++++++++ .../Policies/MaintenanceProviderPolicy.php | 100 ++++++++++++++++++ 7 files changed, 700 insertions(+) create mode 100644 app-modules/inventory-management/src/Policies/AssetExchangePolicy.php create mode 100644 app-modules/inventory-management/src/Policies/AssetLocationPolicy.php create mode 100644 app-modules/inventory-management/src/Policies/AssetPolicy.php create mode 100644 app-modules/inventory-management/src/Policies/AssetStatusPolicy.php create mode 100644 app-modules/inventory-management/src/Policies/AssetTypePolicy.php create mode 100644 app-modules/inventory-management/src/Policies/MaintenanceActivityPolicy.php create mode 100644 app-modules/inventory-management/src/Policies/MaintenanceProviderPolicy.php diff --git a/app-modules/inventory-management/src/Policies/AssetExchangePolicy.php b/app-modules/inventory-management/src/Policies/AssetExchangePolicy.php new file mode 100644 index 0000000000..031744e4f1 --- /dev/null +++ b/app-modules/inventory-management/src/Policies/AssetExchangePolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\AssetExchange; + +class AssetExchangePolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_exchange.view-any', + denyResponse: 'You do not have permission to view asset exchanges.' + ); + } + + public function view(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_exchange.*.view', "asset_exchange.{$assetExchange->id}.view"], + denyResponse: 'You do not have permission to view this asset exchange.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_exchange.create', + denyResponse: 'You do not have permission to create asset exchanges.' + ); + } + + public function update(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_exchange.*.update', "asset_exchange.{$assetExchange->id}.update"], + denyResponse: 'You do not have permission to update this asset exchange.' + ); + } + + public function delete(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_exchange.*.delete', "asset_exchange.{$assetExchange->id}.delete"], + denyResponse: 'You do not have permission to delete this asset exchange.' + ); + } + + public function restore(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_exchange.*.restore', "asset_exchange.{$assetExchange->id}.restore"], + denyResponse: 'You do not have permission to restore this asset exchange.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_exchange.*.force-delete', "asset_exchange.{$assetExchange->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset exchange.' + ); + } +} diff --git a/app-modules/inventory-management/src/Policies/AssetLocationPolicy.php b/app-modules/inventory-management/src/Policies/AssetLocationPolicy.php new file mode 100644 index 0000000000..f6500dc256 --- /dev/null +++ b/app-modules/inventory-management/src/Policies/AssetLocationPolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\AssetLocation; + +class AssetLocationPolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_location.view-any', + denyResponse: 'You do not have permission to view asset locations.' + ); + } + + public function view(Authenticatable $authenticatable, AssetLocation $assetLocation): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_location.*.view', "asset_location.{$assetLocation->id}.view"], + denyResponse: 'You do not have permission to view this asset location.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_location.create', + denyResponse: 'You do not have permission to create asset locations.' + ); + } + + public function update(Authenticatable $authenticatable, AssetLocation $assetLocation): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_location.*.update', "asset_location.{$assetLocation->id}.update"], + denyResponse: 'You do not have permission to update this asset location.' + ); + } + + public function delete(Authenticatable $authenticatable, AssetLocation $assetLocation): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_location.*.delete', "asset_location.{$assetLocation->id}.delete"], + denyResponse: 'You do not have permission to delete this asset location.' + ); + } + + public function restore(Authenticatable $authenticatable, AssetLocation $assetLocation): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_location.*.restore', "asset_location.{$assetLocation->id}.restore"], + denyResponse: 'You do not have permission to restore this asset location.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, AssetLocation $assetLocation): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_location.*.force-delete', "asset_location.{$assetLocation->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset location.' + ); + } +} diff --git a/app-modules/inventory-management/src/Policies/AssetPolicy.php b/app-modules/inventory-management/src/Policies/AssetPolicy.php new file mode 100644 index 0000000000..ec0b8e5140 --- /dev/null +++ b/app-modules/inventory-management/src/Policies/AssetPolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\Asset; + +class AssetPolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset.view-any', + denyResponse: 'You do not have permission to view assets.' + ); + } + + public function view(Authenticatable $authenticatable, Asset $asset): Response + { + return $authenticatable->canOrElse( + abilities: ['asset.*.view', "asset.{$asset->id}.view"], + denyResponse: 'You do not have permission to view this asset.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset.create', + denyResponse: 'You do not have permission to create assets.' + ); + } + + public function update(Authenticatable $authenticatable, Asset $asset): Response + { + return $authenticatable->canOrElse( + abilities: ['asset.*.update', "asset.{$asset->id}.update"], + denyResponse: 'You do not have permission to update this asset.' + ); + } + + public function delete(Authenticatable $authenticatable, Asset $asset): Response + { + return $authenticatable->canOrElse( + abilities: ['asset.*.delete', "asset.{$asset->id}.delete"], + denyResponse: 'You do not have permission to delete this asset.' + ); + } + + public function restore(Authenticatable $authenticatable, Asset $asset): Response + { + return $authenticatable->canOrElse( + abilities: ['asset.*.restore', "asset.{$asset->id}.restore"], + denyResponse: 'You do not have permission to restore this asset.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, Asset $asset): Response + { + return $authenticatable->canOrElse( + abilities: ['asset.*.force-delete', "asset.{$asset->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset.' + ); + } +} diff --git a/app-modules/inventory-management/src/Policies/AssetStatusPolicy.php b/app-modules/inventory-management/src/Policies/AssetStatusPolicy.php new file mode 100644 index 0000000000..1e973501b9 --- /dev/null +++ b/app-modules/inventory-management/src/Policies/AssetStatusPolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\AssetStatus; + +class AssetStatusPolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_status.view-any', + denyResponse: 'You do not have permission to view asset statuses.' + ); + } + + public function view(Authenticatable $authenticatable, AssetStatus $assetStatus): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_status.*.view', "asset_status.{$assetStatus->id}.view"], + denyResponse: 'You do not have permission to view this asset status.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_status.create', + denyResponse: 'You do not have permission to create asset statuses.' + ); + } + + public function update(Authenticatable $authenticatable, AssetStatus $assetStatus): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_status.*.update', "asset_status.{$assetStatus->id}.update"], + denyResponse: 'You do not have permission to update this asset status.' + ); + } + + public function delete(Authenticatable $authenticatable, AssetStatus $assetStatus): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_status.*.delete', "asset_status.{$assetStatus->id}.delete"], + denyResponse: 'You do not have permission to delete this asset status.' + ); + } + + public function restore(Authenticatable $authenticatable, AssetStatus $assetStatus): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_status.*.restore', "asset_status.{$assetStatus->id}.restore"], + denyResponse: 'You do not have permission to restore this asset status.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, AssetStatus $assetStatus): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_status.*.force-delete', "asset_status.{$assetStatus->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset status.' + ); + } +} diff --git a/app-modules/inventory-management/src/Policies/AssetTypePolicy.php b/app-modules/inventory-management/src/Policies/AssetTypePolicy.php new file mode 100644 index 0000000000..952f9140ad --- /dev/null +++ b/app-modules/inventory-management/src/Policies/AssetTypePolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\AssetType; + +class AssetTypePolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_type.view-any', + denyResponse: 'You do not have permission to view asset types.' + ); + } + + public function view(Authenticatable $authenticatable, AssetType $assetType): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_type.*.view', "asset_type.{$assetType->id}.view"], + denyResponse: 'You do not have permission to view this asset type.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_type.create', + denyResponse: 'You do not have permission to create asset types.' + ); + } + + public function update(Authenticatable $authenticatable, AssetType $assetType): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_type.*.update', "asset_type.{$assetType->id}.update"], + denyResponse: 'You do not have permission to update this asset type.' + ); + } + + public function delete(Authenticatable $authenticatable, AssetType $assetType): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_type.*.delete', "asset_type.{$assetType->id}.delete"], + denyResponse: 'You do not have permission to delete this asset type.' + ); + } + + public function restore(Authenticatable $authenticatable, AssetType $assetType): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_type.*.restore', "asset_type.{$assetType->id}.restore"], + denyResponse: 'You do not have permission to restore this asset type.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, AssetType $assetType): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_type.*.force-delete', "asset_type.{$assetType->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset type.' + ); + } +} diff --git a/app-modules/inventory-management/src/Policies/MaintenanceActivityPolicy.php b/app-modules/inventory-management/src/Policies/MaintenanceActivityPolicy.php new file mode 100644 index 0000000000..fe5911d6c3 --- /dev/null +++ b/app-modules/inventory-management/src/Policies/MaintenanceActivityPolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\MaintenanceActivity; + +class MaintenanceActivityPolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'maintenance_activity.view-any', + denyResponse: 'You do not have permission to view maintenance activities.' + ); + } + + public function view(Authenticatable $authenticatable, MaintenanceActivity $maintenanceActivity): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_activity.*.view', "maintenance_activity.{$maintenanceActivity->id}.view"], + denyResponse: 'You do not have permission to view this maintenance activity.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'maintenance_activity.create', + denyResponse: 'You do not have permission to create maintenance activities.' + ); + } + + public function update(Authenticatable $authenticatable, MaintenanceActivity $maintenanceActivity): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_activity.*.update', "maintenance_activity.{$maintenanceActivity->id}.update"], + denyResponse: 'You do not have permission to update this maintenance activity.' + ); + } + + public function delete(Authenticatable $authenticatable, MaintenanceActivity $maintenanceActivity): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_activity.*.delete', "maintenance_activity.{$maintenanceActivity->id}.delete"], + denyResponse: 'You do not have permission to delete this maintenance activity.' + ); + } + + public function restore(Authenticatable $authenticatable, MaintenanceActivity $maintenanceActivity): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_activity.*.restore', "maintenance_activity.{$maintenanceActivity->id}.restore"], + denyResponse: 'You do not have permission to restore this maintenance activity.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, MaintenanceActivity $maintenanceActivity): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_activity.*.force-delete', "maintenance_activity.{$maintenanceActivity->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this maintenance activity.' + ); + } +} diff --git a/app-modules/inventory-management/src/Policies/MaintenanceProviderPolicy.php b/app-modules/inventory-management/src/Policies/MaintenanceProviderPolicy.php new file mode 100644 index 0000000000..fab3fb32a0 --- /dev/null +++ b/app-modules/inventory-management/src/Policies/MaintenanceProviderPolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\MaintenanceProvider; + +class MaintenanceProviderPolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'maintenance_provider.view-any', + denyResponse: 'You do not have permission to view maintenance providers.' + ); + } + + public function view(Authenticatable $authenticatable, MaintenanceProvider $maintenanceProvider): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_provider.*.view', "maintenance_provider.{$maintenanceProvider->id}.view"], + denyResponse: 'You do not have permission to view this maintenance provider.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'maintenance_provider.create', + denyResponse: 'You do not have permission to create maintenance providers.' + ); + } + + public function update(Authenticatable $authenticatable, MaintenanceProvider $maintenanceProvider): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_provider.*.update', "maintenance_provider.{$maintenanceProvider->id}.update"], + denyResponse: 'You do not have permission to update this maintenance provider.' + ); + } + + public function delete(Authenticatable $authenticatable, MaintenanceProvider $maintenanceProvider): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_provider.*.delete', "maintenance_provider.{$maintenanceProvider->id}.delete"], + denyResponse: 'You do not have permission to delete this maintenance provider.' + ); + } + + public function restore(Authenticatable $authenticatable, MaintenanceProvider $maintenanceProvider): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_provider.*.restore', "maintenance_provider.{$maintenanceProvider->id}.restore"], + denyResponse: 'You do not have permission to restore this maintenance provider.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, MaintenanceProvider $maintenanceProvider): Response + { + return $authenticatable->canOrElse( + abilities: ['maintenance_provider.*.force-delete', "maintenance_provider.{$maintenanceProvider->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this maintenance provider.' + ); + } +} From d6e7cca8a31daa17715f45653f9ed1db637e5948 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Tue, 2 Jan 2024 13:45:43 -0500 Subject: [PATCH 14/56] Utilize two model system. --- .../factories/AssetCheckInFactory.php | 45 ++++++++++++++ .../factories/AssetCheckOutFactory.php | 53 ++++++++++++++++ .../database/factories/AssetStatusFactory.php | 2 + ...8_174428_create_asset_check_ins_table.php} | 13 ++-- ...8_174437_create_asset_check_outs_table.php | 25 ++++++++ .../database/seeders/AssetSeeder.php | 11 +++- .../database/seeders/AssetStatusSeeder.php | 8 ++- .../src/Enums/AssetExchangeType.php | 50 --------------- .../inventory-management/src/Models/Asset.php | 22 +++---- .../src/Models/AssetCheckIn.php | 59 ++++++++++++++++++ .../src/Models/AssetCheckOut.php | 61 +++++++++++++++++++ .../src/Models/AssetExchange.php | 45 -------------- .../src/Models/AssetStatus.php | 8 +-- .../InventoryManagementServiceProvider.php | 4 ++ 14 files changed, 285 insertions(+), 121 deletions(-) create mode 100644 app-modules/inventory-management/database/factories/AssetCheckInFactory.php create mode 100644 app-modules/inventory-management/database/factories/AssetCheckOutFactory.php rename app-modules/inventory-management/database/migrations/{2023_12_28_131317_create_asset_exchanges_table.php => 2023_12_28_174428_create_asset_check_ins_table.php} (52%) create mode 100644 app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php delete mode 100644 app-modules/inventory-management/src/Enums/AssetExchangeType.php create mode 100644 app-modules/inventory-management/src/Models/AssetCheckIn.php create mode 100644 app-modules/inventory-management/src/Models/AssetCheckOut.php delete mode 100644 app-modules/inventory-management/src/Models/AssetExchange.php diff --git a/app-modules/inventory-management/database/factories/AssetCheckInFactory.php b/app-modules/inventory-management/database/factories/AssetCheckInFactory.php new file mode 100644 index 0000000000..793d21673d --- /dev/null +++ b/app-modules/inventory-management/database/factories/AssetCheckInFactory.php @@ -0,0 +1,45 @@ + + */ +class AssetCheckInFactory extends Factory +{ + public function definition(): array + { + $checkedOutBy = User::factory()->create(); + + return [ + 'asset_id' => Asset::factory(), + 'checked_in_by_type' => $checkedOutBy->getMorphClass(), + 'checked_in_by_id' => $checkedOutBy->getKey(), + 'checked_in_from_type' => fake()->randomElement([ + (new Student())->getMorphClass(), + (new Prospect())->getMorphClass(), + ]), + 'checked_in_from_id' => function (array $attributes) { + $checkedInFromClass = Relation::getMorphedModel($attributes['checked_in_from_type']); + + /** @var Student|Prospect $senderModel */ + $checkedInFromModel = new $checkedInFromClass(); + + $checkedInFromModel = $checkedInFromClass === Student::class + ? Student::inRandomOrder()->first() ?? Student::factory()->create() + : $checkedInFromModel::factory()->create(); + + return $checkedInFromModel->getKey(); + }, + 'checked_in_at' => fake()->dateTimeBetween('-1 year', 'now'), + 'notes' => fake()->paragraph(), + ]; + } +} diff --git a/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php b/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php new file mode 100644 index 0000000000..f4e1d061c3 --- /dev/null +++ b/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php @@ -0,0 +1,53 @@ + + */ +class AssetCheckOutFactory extends Factory +{ + public function definition(): array + { + $checkedOutBy = User::factory()->create(); + + return [ + 'asset_id' => Asset::factory(), + // TODO Add variance to this column so that some check outs do not have corresponding check ins + 'asset_check_in_id' => null, + 'checked_out_by_type' => $checkedOutBy->getMorphClass(), + 'checked_out_by_id' => $checkedOutBy->getKey(), + 'checked_out_to_type' => fake()->randomElement([ + (new Student())->getMorphClass(), + (new Prospect())->getMorphClass(), + ]), + 'checked_out_to_id' => function (array $attributes) { + $checkedOutToClass = Relation::getMorphedModel($attributes['checked_out_to_type']); + + /** @var Student|Prospect $senderModel */ + $checkedOutToModel = new $checkedOutToClass(); + + $checkedOutToModel = $checkedOutToClass === Student::class + ? Student::inRandomOrder()->first() ?? Student::factory()->create() + : $checkedOutToModel::factory()->create(); + + return $checkedOutToModel->getKey(); + }, + 'checked_out_at' => fake()->dateTimeBetween('-1 year', 'now'), + 'expected_check_in_at' => function (array $attributes) { + $checkedOutAt = Carbon::parse($attributes['checked_out_at']); + + return fake()->dateTimeBetween($checkedOutAt->addDays(1), $checkedOutAt->addDays(50)); + }, + 'notes' => fake()->paragraph(), + ]; + } +} diff --git a/app-modules/inventory-management/database/factories/AssetStatusFactory.php b/app-modules/inventory-management/database/factories/AssetStatusFactory.php index 75ea75e646..412da2f51c 100644 --- a/app-modules/inventory-management/database/factories/AssetStatusFactory.php +++ b/app-modules/inventory-management/database/factories/AssetStatusFactory.php @@ -37,6 +37,7 @@ namespace AdvisingApp\InventoryManagement\Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; +use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; /** * @extends \Illuminate\Database\Eloquent\Factories\Factory<\AdvisingApp\InventoryManagement\Models\AssetStatus> @@ -46,6 +47,7 @@ class AssetStatusFactory extends Factory public function definition(): array { return [ + 'classification' => SystemAssetStatusClassification::Unavailable, 'name' => fake()->word(), ]; } diff --git a/app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php b/app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php similarity index 52% rename from app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php rename to app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php index d474c186f1..08c435f4bb 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_28_131317_create_asset_exchanges_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php @@ -7,14 +7,15 @@ return new class () extends Migration { public function up(): void { - Schema::create('asset_exchanges', function (Blueprint $table) { + Schema::create('asset_check_ins', function (Blueprint $table) { $table->uuid('id')->primary(); $table->foreignUuid('asset_id')->constrained('assets'); - $table->string('type'); - $table->string('performed_by_type')->nullable(); - $table->string('performed_by_id')->nullable(); - $table->string('for_type'); - $table->string('for_id'); + $table->string('checked_in_by_type')->nullable(); + $table->string('checked_in_by_id')->nullable(); + $table->string('checked_in_from_type'); + $table->string('checked_in_from_id'); + $table->timestamp('checked_in_at'); + $table->longText('notes')->nullable(); $table->timestamps(); $table->softDeletes(); }); diff --git a/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php b/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php new file mode 100644 index 0000000000..a37094dcd4 --- /dev/null +++ b/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php @@ -0,0 +1,25 @@ +uuid('id')->primary(); + $table->foreignUuid('asset_id')->constrained('assets'); + $table->foreignUuid('asset_check_in_id')->nullable()->constrained('asset_check_ins'); + $table->string('checked_out_by_type')->nullable(); + $table->string('checked_out_by_id')->nullable(); + $table->string('checked_out_to_type'); + $table->string('checked_out_to_id'); + $table->timestamp('checked_out_at'); + $table->timestamp('expected_check_in_at')->nullable(); + $table->longText('notes')->nullable(); + $table->timestamps(); + $table->softDeletes(); + }); + } +}; diff --git a/app-modules/inventory-management/database/seeders/AssetSeeder.php b/app-modules/inventory-management/database/seeders/AssetSeeder.php index d5638da918..4baa6c6f61 100644 --- a/app-modules/inventory-management/database/seeders/AssetSeeder.php +++ b/app-modules/inventory-management/database/seeders/AssetSeeder.php @@ -38,6 +38,8 @@ use Illuminate\Database\Seeder; use AdvisingApp\InventoryManagement\Models\Asset; +use AdvisingApp\InventoryManagement\Models\AssetCheckIn; +use AdvisingApp\InventoryManagement\Models\AssetCheckOut; use AdvisingApp\InventoryManagement\Models\MaintenanceActivity; class AssetSeeder extends Seeder @@ -48,13 +50,18 @@ public function run(): void ->count(10) ->create() ->each(function (Asset $asset) { - $maintenanceActivitiesCount = rand(0, 10); + $entityCount = rand(0, 10); - for ($i = 0; $i < $maintenanceActivitiesCount; $i++) { + for ($i = 0; $i < $entityCount; $i++) { MaintenanceActivity::factory() ->randomizeState() ->for($asset, 'asset') ->create(); + + AssetCheckOut::factory() + ->has(AssetCheckIn::factory(), 'checkIn') + ->for($asset, 'asset') + ->create(); } }); } diff --git a/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php b/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php index 5ae922356b..16ddff9f5e 100644 --- a/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php +++ b/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php @@ -38,6 +38,7 @@ use Illuminate\Database\Seeder; use AdvisingApp\InventoryManagement\Models\AssetStatus; +use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; class AssetStatusSeeder extends Seeder { @@ -46,16 +47,17 @@ public function run(): void AssetStatus::factory() ->createMany( [ + [ + 'name' => 'Available', + 'classification' => SystemAssetStatusClassification::Available, + ], ['name' => 'In Use'], - ['name' => 'Available'], ['name' => 'Under Maintenance'], ['name' => 'Out of Service'], ['name' => 'Reserved'], - ['name' => 'On Loan'], ['name' => 'Awaiting Repair'], ['name' => 'Lost'], ['name' => 'Damaged'], - ['name' => 'New'], ] ); } diff --git a/app-modules/inventory-management/src/Enums/AssetExchangeType.php b/app-modules/inventory-management/src/Enums/AssetExchangeType.php deleted file mode 100644 index 9af8a53029..0000000000 --- a/app-modules/inventory-management/src/Enums/AssetExchangeType.php +++ /dev/null @@ -1,50 +0,0 @@ - - - Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. - - Advising App™ is licensed under the Elastic License 2.0. For more details, - see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. - - Notice: - - - You may not provide the software to third parties as a hosted or managed - service, where the service provides users with access to any substantial set of - the features or functionality of the software. - - You may not move, change, disable, or circumvent the license key functionality - in the software, and you may not remove or obscure any functionality in the - software that is protected by the license key. - - You may not alter, remove, or obscure any licensing, copyright, or other notices - of the licensor in the software. Any use of the licensor’s trademarks is subject - to applicable law. - - Canyon GBS LLC respects the intellectual property rights of others and expects the - same in return. Canyon GBS™ and Advising App™ are registered trademarks of - Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks - vigorously. - - The software solution, including services, infrastructure, and code, is offered as a - Software as a Service (SaaS) by Canyon GBS LLC. - - Use of this software implies agreement to the license terms and conditions as stated - in the Elastic License 2.0. - - For more information or inquiries please visit our website at - https://www.canyongbs.com or contact us via email at legal@canyongbs.com. - - -*/ - -namespace AdvisingApp\InventoryManagement\Enums; - -use Filament\Support\Contracts\HasLabel; - -enum AssetExchangeType: string implements HasLabel -{ - case CheckIn = 'check_in'; - case CheckOut = 'check_out'; - - public function getLabel(): ?string - { - return $this->name; - } -} diff --git a/app-modules/inventory-management/src/Models/Asset.php b/app-modules/inventory-management/src/Models/Asset.php index 02c7dd281f..ec2629e1b3 100644 --- a/app-modules/inventory-management/src/Models/Asset.php +++ b/app-modules/inventory-management/src/Models/Asset.php @@ -36,13 +36,13 @@ namespace AdvisingApp\InventoryManagement\Models; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; -use AdvisingApp\InventoryManagement\Enums\AssetExchangeType; use App\Models\BaseModel; -use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\SoftDeletes; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; /** * @mixin IdeHelperAsset @@ -82,18 +82,18 @@ public function maintenanceActivities(): HasMany return $this->hasMany(MaintenanceActivity::class, 'asset_id'); } - public function exchanges(): HasMany + public function checkOuts(): HasMany { - return $this->hasMany(AssetExchange::class, 'asset_id'); + return $this->hasMany(AssetCheckOut::class, 'asset_id'); } - public function checkOuts(): HasMany + public function checkIns(): HasMany { - return $this->exchanges()->where('type', AssetExchangeType::CheckOut); + return $this->hasMany(AssetCheckIn::class, 'asset_id'); } - public function checkIns(): HasMany + public function isAvailable(): bool { - return $this->exchanges()->where('type', AssetExchangeType::CheckIn); + return $this->status->classification === SystemAssetStatusClassification::Available; } } diff --git a/app-modules/inventory-management/src/Models/AssetCheckIn.php b/app-modules/inventory-management/src/Models/AssetCheckIn.php new file mode 100644 index 0000000000..edd1f6dca2 --- /dev/null +++ b/app-modules/inventory-management/src/Models/AssetCheckIn.php @@ -0,0 +1,59 @@ + 'datetime', + ]; + + public function asset(): BelongsTo + { + return $this->belongsTo(Asset::class, 'asset_id'); + } + + public function checkedInBy(): MorphTo + { + return $this->morphTo( + name: 'checked_in_by', + type: 'checked_in_by_type', + id: 'checked_in_by_id', + ); + } + + public function checkedInFrom(): MorphTo + { + return $this->morphTo( + name: 'checked_in_from', + type: 'checked_in_from_type', + id: 'checked_in_from_id', + ); + } + + public function checkOut(): HasOne + { + return $this->hasOne(AssetCheckOut::class); + } +} diff --git a/app-modules/inventory-management/src/Models/AssetCheckOut.php b/app-modules/inventory-management/src/Models/AssetCheckOut.php new file mode 100644 index 0000000000..dad253e8c2 --- /dev/null +++ b/app-modules/inventory-management/src/Models/AssetCheckOut.php @@ -0,0 +1,61 @@ + 'datetime', + 'expected_check_in_at' => 'datetime', + ]; + + public function asset(): BelongsTo + { + return $this->belongsTo(Asset::class, 'asset_id'); + } + + public function checkedOutBy(): MorphTo + { + return $this->morphTo( + name: 'checked_out_by', + type: 'checked_out_by_type', + id: 'checked_out_by_id', + ); + } + + public function checkedOutTo(): MorphTo + { + return $this->morphTo( + name: 'checked_out_to', + type: 'checked_out_to_type', + id: 'checked_out_to_id', + ); + } + + public function checkIn(): BelongsTo + { + return $this->belongsTo(AssetCheckIn::class); + } +} diff --git a/app-modules/inventory-management/src/Models/AssetExchange.php b/app-modules/inventory-management/src/Models/AssetExchange.php deleted file mode 100644 index 41107d7e83..0000000000 --- a/app-modules/inventory-management/src/Models/AssetExchange.php +++ /dev/null @@ -1,45 +0,0 @@ - AssetExchangeType::class, - ]; - - public function asset(): BelongsTo - { - return $this->belongsTo(Asset::class, 'asset_id'); - } - - public function scopeCheckIn(Builder $query): void - { - $query->where('type', AssetExchangeType::CheckIn); - } - - public function scopeCheckOut(Builder $query): void - { - $query->where('type', AssetExchangeType::CheckOut); - } -} diff --git a/app-modules/inventory-management/src/Models/AssetStatus.php b/app-modules/inventory-management/src/Models/AssetStatus.php index ad32d6023a..524f5372c9 100644 --- a/app-modules/inventory-management/src/Models/AssetStatus.php +++ b/app-modules/inventory-management/src/Models/AssetStatus.php @@ -36,12 +36,12 @@ namespace AdvisingApp\InventoryManagement\Models; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; -use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; use App\Models\BaseModel; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\SoftDeletes; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\HasMany; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; /** * @mixin IdeHelperAssetStatus diff --git a/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php b/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php index ee84ace5b0..52739c94ec 100644 --- a/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php +++ b/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php @@ -43,6 +43,8 @@ use AdvisingApp\InventoryManagement\Models\AssetType; use AdvisingApp\InventoryManagement\Models\AssetStatus; use AdvisingApp\Authorization\AuthorizationRoleRegistry; +use AdvisingApp\InventoryManagement\Models\AssetCheckIn; +use AdvisingApp\InventoryManagement\Models\AssetCheckOut; use AdvisingApp\InventoryManagement\Models\AssetLocation; use AdvisingApp\Authorization\AuthorizationPermissionRegistry; use AdvisingApp\InventoryManagement\InventoryManagementPlugin; @@ -59,6 +61,8 @@ public function register() public function boot() { Relation::morphMap([ + 'asset_check_in' => AssetCheckIn::class, + 'asset_check_out' => AssetCheckOut::class, 'asset_location' => AssetLocation::class, 'asset_status' => AssetStatus::class, 'asset_type' => AssetType::class, From 3f330427176b4784d76514126d6cdfc83f2ee773 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 07:39:00 -0500 Subject: [PATCH 15/56] Add check out action. --- .../database/seeders/AssetStatusSeeder.php | 5 +- .../Enums/SystemAssetStatusClassification.php | 8 +- .../Actions/CheckOutAssetHeaderAction.php | 95 +++++++++++++++++++ .../AssetResource/Pages/ViewAsset.php | 9 ++ .../inventory-management/src/Models/Asset.php | 16 +++- 5 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php diff --git a/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php b/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php index 16ddff9f5e..e722caff2b 100644 --- a/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php +++ b/app-modules/inventory-management/database/seeders/AssetStatusSeeder.php @@ -51,7 +51,10 @@ public function run(): void 'name' => 'Available', 'classification' => SystemAssetStatusClassification::Available, ], - ['name' => 'In Use'], + [ + 'name' => 'In Use', + 'classification' => SystemAssetStatusClassification::CheckedOut, + ], ['name' => 'Under Maintenance'], ['name' => 'Out of Service'], ['name' => 'Reserved'], diff --git a/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php b/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php index d1b153e600..7d4447615d 100644 --- a/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php +++ b/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php @@ -42,12 +42,18 @@ enum SystemAssetStatusClassification: string implements HasLabel { case Available = 'available'; + // TODO Implement a rule that only one asset status can be classified as this + case CheckedOut = 'checked_out'; + case Unavailable = 'unavailable'; case Custom = 'custom'; public function getLabel(): ?string { - return $this->name; + return match ($this) { + self::CheckedOut => 'Checked Out', + default => $this->name + }; } } diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php new file mode 100644 index 0000000000..b65d222e75 --- /dev/null +++ b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php @@ -0,0 +1,95 @@ +button(); + + $this->label(__('Check Out')); + + /** @var Asset $asset */ + $asset = $this->getRecord(); + + $this->modalHeading(__("Check out {$asset->name}")); + + $this->modalSubmitActionLabel(__('Done')); + + $this->successNotificationTitle(__("Successfully checked out {$asset->name}")); + + $this->form([ + Radio::make('checked_out_to_type') + ->label('Check out to') + ->options([ + Student::class => 'Student', + Prospect::class => 'Prospect', + ]) + ->default(Student::class) + ->required() + ->live(), + Select::make('checked_out_to_id') + ->label(fn (Get $get): string => match ($get('checked_out_to_type')) { + Student::class => 'Select Student', + Prospect::class => 'Select Prospect', + }) + ->visible(fn (Get $get): bool => filled($get('checked_out_to_type'))) + ->getSearchResultsUsing(function (string $search, Get $get) { + return match ($get('checked_out_to_type')) { + Student::class => Student::where('full_name', 'like', "%{$search}%")->pluck('full_name', 'sisid')->toArray(), + Prospect::class => Prospect::where('full_name', 'like', "%{$search}%")->pluck('full_name', 'id')->toArray(), + }; + }) + ->searchable() + ->required(), + Textarea::make('notes') + ->autofocus() + ->required(), + DateTimePicker::make('expected_check_in_at') + ->label('Expected Return Date'), + ]); + + $this->action(function (array $data): void { + /** @var Asset $asset */ + $asset = $this->getRecord(); + + if (! $asset->isAvailable()) { + $this->failure(); + } + + $asset->checkOuts()->create([ + 'checked_out_by_type' => auth()->user()?->getMorphClass(), + 'checked_out_by_id' => auth()->user()?->id, + 'checked_out_to_type' => (new $data['checked_out_to_type']())->getMorphClass(), + 'checked_out_to_id' => $data['checked_out_to_id'], + 'notes' => $data['notes'], + 'checked_out_at' => now(), + 'expected_check_in_at' => $data['expected_check_in_at'], + ]); + + // TODO We may want to move this to an observer in order to clean up... + $checkedOutStatus = AssetStatus::where('classification', SystemAssetStatusClassification::CheckedOut)->first(); + + $asset->update([ + 'status_id' => $checkedOutStatus->id, + ]); + + $this->success(); + }); + } +} diff --git a/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php b/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php index aaaa2de57b..deedb2c68d 100644 --- a/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php +++ b/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php @@ -41,7 +41,9 @@ use Filament\Resources\Pages\ViewRecord; use Filament\Infolists\Components\Section; use Filament\Infolists\Components\TextEntry; +use AdvisingApp\InventoryManagement\Models\Asset; use AdvisingApp\InventoryManagement\Filament\Resources\AssetResource; +use AdvisingApp\InventoryManagement\Filament\Actions\CheckOutAssetHeaderAction; class ViewAsset extends ViewRecord { @@ -71,6 +73,13 @@ protected function getHeaderActions(): array { return [ EditAction::make(), + CheckOutAssetHeaderAction::make('check-out') + ->visible(function () { + /** @var Asset $asset */ + $asset = $this->getRecord(); + + return $asset->isAvailable(); + }), ]; } } diff --git a/app-modules/inventory-management/src/Models/Asset.php b/app-modules/inventory-management/src/Models/Asset.php index ec2629e1b3..a3d240dfd1 100644 --- a/app-modules/inventory-management/src/Models/Asset.php +++ b/app-modules/inventory-management/src/Models/Asset.php @@ -39,6 +39,7 @@ use App\Models\BaseModel; use OwenIt\Auditing\Contracts\Auditable; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; @@ -87,6 +88,18 @@ public function checkOuts(): HasMany return $this->hasMany(AssetCheckOut::class, 'asset_id'); } + public function latestCheckOut(): HasOne + { + return $this->hasOne(AssetCheckOut::class, 'asset_id') + ->oldest('checked_out_at'); + } + + public function latestCheckIn(): HasOne + { + return $this->hasOne(AssetCheckIn::class, 'asset_id') + ->latest('checked_in_at'); + } + public function checkIns(): HasMany { return $this->hasMany(AssetCheckIn::class, 'asset_id'); @@ -94,6 +107,7 @@ public function checkIns(): HasMany public function isAvailable(): bool { - return $this->status->classification === SystemAssetStatusClassification::Available; + return $this->status->classification === SystemAssetStatusClassification::Available + && is_null($this->latestCheckOut->asset_check_in_id); } } From fa3bff3cfd4d365e5a84b76b3b6c0dae8b94ed26 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 08:06:33 -0500 Subject: [PATCH 16/56] Add check in action. --- .../Providers/EngagementServiceProvider.php | 4 +- .../Enums/SystemAssetStatusClassification.php | 1 + .../Actions/CheckInAssetHeaderAction.php | 64 +++++++++++++++++++ .../AssetResource/Pages/ViewAsset.php | 8 +++ .../inventory-management/src/Models/Asset.php | 13 +++- .../src/Observers/AssetCheckInObserver.php | 52 +++++++++++++++ .../InventoryManagementServiceProvider.php | 8 +++ 7 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php create mode 100644 app-modules/inventory-management/src/Observers/AssetCheckInObserver.php diff --git a/app-modules/engagement/src/Providers/EngagementServiceProvider.php b/app-modules/engagement/src/Providers/EngagementServiceProvider.php index c37579c893..5f9f784093 100644 --- a/app-modules/engagement/src/Providers/EngagementServiceProvider.php +++ b/app-modules/engagement/src/Providers/EngagementServiceProvider.php @@ -84,9 +84,9 @@ public function boot(): void ->withoutOverlapping(); }); - $this->registerRolesAndPermissions(); - $this->registerObservers(); + + $this->registerRolesAndPermissions(); } public function registerObservers(): void diff --git a/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php b/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php index 7d4447615d..ba9704cb95 100644 --- a/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php +++ b/app-modules/inventory-management/src/Enums/SystemAssetStatusClassification.php @@ -40,6 +40,7 @@ enum SystemAssetStatusClassification: string implements HasLabel { + // TODO Implement a rule that only one asset status can be classified as this case Available = 'available'; // TODO Implement a rule that only one asset status can be classified as this diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php new file mode 100644 index 0000000000..e14ef6b132 --- /dev/null +++ b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php @@ -0,0 +1,64 @@ +button(); + + $this->label(__('Check In')); + + /** @var Asset $asset */ + $asset = $this->getRecord(); + + $this->modalHeading(__("Check in {$asset->name}")); + + $this->modalSubmitActionLabel(__('Done')); + + $this->successNotificationTitle(__("Successfully checked in {$asset->name}")); + + $this->form([ + Textarea::make('notes') + ->autofocus() + ->required(), + ]); + + $this->action(function (array $data): void { + /** @var Asset $asset */ + $asset = $this->getRecord(); + + if (! $asset->isAvailable()) { + $this->failure(); + } + + $asset->checkIns()->create([ + 'checked_in_by_type' => auth()->user()?->getMorphClass(), + 'checked_in_by_id' => auth()->user()?->id, + // TODO Should we still have this be configurable? Or should the expectation be that this information is the same as the latest check out? + 'checked_in_from_type' => $asset->latestCheckOut->checked_out_to_type, + 'checked_in_from_id' => $asset->latestCheckOut->checked_out_to_id, + 'notes' => $data['notes'], + 'checked_in_at' => now(), + ]); + + // TODO We may want to move this to an observer in order to clean up... + $checkedInStatus = AssetStatus::where('classification', SystemAssetStatusClassification::Available)->first(); + + $asset->update([ + 'status_id' => $checkedInStatus->id, + ]); + + $this->success(); + }); + } +} diff --git a/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php b/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php index deedb2c68d..db278be7fb 100644 --- a/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php +++ b/app-modules/inventory-management/src/Filament/Resources/AssetResource/Pages/ViewAsset.php @@ -43,6 +43,7 @@ use Filament\Infolists\Components\TextEntry; use AdvisingApp\InventoryManagement\Models\Asset; use AdvisingApp\InventoryManagement\Filament\Resources\AssetResource; +use AdvisingApp\InventoryManagement\Filament\Actions\CheckInAssetHeaderAction; use AdvisingApp\InventoryManagement\Filament\Actions\CheckOutAssetHeaderAction; class ViewAsset extends ViewRecord @@ -80,6 +81,13 @@ protected function getHeaderActions(): array return $asset->isAvailable(); }), + CheckInAssetHeaderAction::make('check-in') + ->visible(function () { + /** @var Asset $asset */ + $asset = $this->getRecord(); + + return $asset->isCheckedOut(); + }), ]; } } diff --git a/app-modules/inventory-management/src/Models/Asset.php b/app-modules/inventory-management/src/Models/Asset.php index a3d240dfd1..80e673b408 100644 --- a/app-modules/inventory-management/src/Models/Asset.php +++ b/app-modules/inventory-management/src/Models/Asset.php @@ -108,6 +108,17 @@ public function checkIns(): HasMany public function isAvailable(): bool { return $this->status->classification === SystemAssetStatusClassification::Available - && is_null($this->latestCheckOut->asset_check_in_id); + && ! is_null($this->latestCheckOut?->asset_check_in_id); + } + + public function isNotAvailable(): bool + { + return ! $this->isAvailable(); + } + + public function isCheckedOut(): bool + { + return $this->status->classification === SystemAssetStatusClassification::CheckedOut + && is_null($this->latestCheckOut?->asset_check_in_id); } } diff --git a/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php b/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php new file mode 100644 index 0000000000..54d9e4fa18 --- /dev/null +++ b/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php @@ -0,0 +1,52 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Observers; + +use AdvisingApp\InventoryManagement\Models\AssetCheckIn; + +class AssetCheckInObserver +{ + public function created(AssetCheckIn $checkIn): void + { + ray('AssetCheckInObserver::created()'); + ray($checkIn->asset->latestCheckOut); + + $checkIn->asset->latestCheckOut->update([ + 'asset_check_in_id' => $checkIn->id, + ]); + } +} diff --git a/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php b/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php index 52739c94ec..bed4974244 100644 --- a/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php +++ b/app-modules/inventory-management/src/Providers/InventoryManagementServiceProvider.php @@ -50,6 +50,7 @@ use AdvisingApp\InventoryManagement\InventoryManagementPlugin; use AdvisingApp\InventoryManagement\Models\MaintenanceActivity; use AdvisingApp\InventoryManagement\Models\MaintenanceProvider; +use AdvisingApp\InventoryManagement\Observers\AssetCheckInObserver; class InventoryManagementServiceProvider extends ServiceProvider { @@ -71,9 +72,16 @@ public function boot() 'maintenance_provider' => MaintenanceProvider::class, ]); + $this->registerObservers(); + $this->registerRolesAndPermissions(); } + public function registerObservers(): void + { + AssetCheckIn::observe(AssetCheckInObserver::class); + } + protected function registerRolesAndPermissions() { $permissionRegistry = app(AuthorizationPermissionRegistry::class); From 8175cf1185ae27bc6dc4dc4a06b6afc06899e54a Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 08:15:54 -0500 Subject: [PATCH 17/56] Make status configurable on check in. --- .../Actions/CheckInAssetHeaderAction.php | 18 +++++++++++++----- .../Actions/CheckOutAssetHeaderAction.php | 3 +-- .../src/Models/AssetStatus.php | 10 ++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php index e14ef6b132..4b7161533f 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php @@ -3,10 +3,11 @@ namespace AdvisingApp\InventoryManagement\Filament\Actions; use Filament\Actions\Action; +use Filament\Forms\Components\Select; use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\DateTimePicker; use AdvisingApp\InventoryManagement\Models\Asset; use AdvisingApp\InventoryManagement\Models\AssetStatus; -use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; class CheckInAssetHeaderAction extends Action { @@ -31,6 +32,16 @@ protected function setUp(): void Textarea::make('notes') ->autofocus() ->required(), + Select::make('status_id') + ->relationship('status', 'name') + ->preload() + ->label('Status') + ->default(AssetStatus::available()->first()->id) + ->required() + ->exists((new AssetStatus())->getTable(), 'id'), + DateTimePicker::make('checked_in_at') + ->label('Checked in at') + ->default(now()), ]); $this->action(function (array $data): void { @@ -51,11 +62,8 @@ protected function setUp(): void 'checked_in_at' => now(), ]); - // TODO We may want to move this to an observer in order to clean up... - $checkedInStatus = AssetStatus::where('classification', SystemAssetStatusClassification::Available)->first(); - $asset->update([ - 'status_id' => $checkedInStatus->id, + 'status_id' => $data['status_id'], ]); $this->success(); diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php index b65d222e75..9bb252cdd5 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php @@ -12,7 +12,6 @@ use AdvisingApp\StudentDataModel\Models\Student; use AdvisingApp\InventoryManagement\Models\Asset; use AdvisingApp\InventoryManagement\Models\AssetStatus; -use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; class CheckOutAssetHeaderAction extends Action { @@ -83,7 +82,7 @@ protected function setUp(): void ]); // TODO We may want to move this to an observer in order to clean up... - $checkedOutStatus = AssetStatus::where('classification', SystemAssetStatusClassification::CheckedOut)->first(); + $checkedOutStatus = AssetStatus::checkedOut()->first(); $asset->update([ 'status_id' => $checkedOutStatus->id, diff --git a/app-modules/inventory-management/src/Models/AssetStatus.php b/app-modules/inventory-management/src/Models/AssetStatus.php index 524f5372c9..85e04ca8ce 100644 --- a/app-modules/inventory-management/src/Models/AssetStatus.php +++ b/app-modules/inventory-management/src/Models/AssetStatus.php @@ -64,4 +64,14 @@ public function assets(): HasMany { return $this->hasMany(Asset::class, 'status_id'); } + + public function scopeAvailable(): void + { + $this->where('classification', SystemAssetStatusClassification::Available); + } + + public function scopeCheckedOut(): void + { + $this->where('classification', SystemAssetStatusClassification::CheckedOut); + } } From 0b7db9ee758ad7690f621829ffe0ed2cf325dfdf Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 08:24:17 -0500 Subject: [PATCH 18/56] Clean up action validation. --- .../inventory-management/database/seeders/AssetSeeder.php | 7 ------- .../src/Filament/Actions/CheckInAssetHeaderAction.php | 5 ++--- .../src/Filament/Actions/CheckOutAssetHeaderAction.php | 3 +-- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/app-modules/inventory-management/database/seeders/AssetSeeder.php b/app-modules/inventory-management/database/seeders/AssetSeeder.php index 4baa6c6f61..9dc2eab33c 100644 --- a/app-modules/inventory-management/database/seeders/AssetSeeder.php +++ b/app-modules/inventory-management/database/seeders/AssetSeeder.php @@ -38,8 +38,6 @@ use Illuminate\Database\Seeder; use AdvisingApp\InventoryManagement\Models\Asset; -use AdvisingApp\InventoryManagement\Models\AssetCheckIn; -use AdvisingApp\InventoryManagement\Models\AssetCheckOut; use AdvisingApp\InventoryManagement\Models\MaintenanceActivity; class AssetSeeder extends Seeder @@ -57,11 +55,6 @@ public function run(): void ->randomizeState() ->for($asset, 'asset') ->create(); - - AssetCheckOut::factory() - ->has(AssetCheckIn::factory(), 'checkIn') - ->for($asset, 'asset') - ->create(); } }); } diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php index 4b7161533f..2c2b3da131 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php @@ -30,8 +30,7 @@ protected function setUp(): void $this->form([ Textarea::make('notes') - ->autofocus() - ->required(), + ->autofocus(), Select::make('status_id') ->relationship('status', 'name') ->preload() @@ -59,7 +58,7 @@ protected function setUp(): void 'checked_in_from_type' => $asset->latestCheckOut->checked_out_to_type, 'checked_in_from_id' => $asset->latestCheckOut->checked_out_to_id, 'notes' => $data['notes'], - 'checked_in_at' => now(), + 'checked_in_at' => $data['checked_in_at'] ?? now(), ]); $asset->update([ diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php index 9bb252cdd5..59d59532a7 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php @@ -57,8 +57,7 @@ protected function setUp(): void ->searchable() ->required(), Textarea::make('notes') - ->autofocus() - ->required(), + ->autofocus(), DateTimePicker::make('expected_check_in_at') ->label('Expected Return Date'), ]); From 1f07cfb3be72de94b99384a878006cf8b4c2ceba Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 08:29:11 -0500 Subject: [PATCH 19/56] Update policies, roles. --- .../config/roles/api/inventory_management.php | 6 ++ .../config/roles/web/inventory_management.php | 6 ++ ...hangePolicy.php => AssetCheckInPolicy.php} | 42 ++++---- .../src/Policies/AssetCheckOutPolicy.php | 100 ++++++++++++++++++ 4 files changed, 133 insertions(+), 21 deletions(-) rename app-modules/inventory-management/src/Policies/{AssetExchangePolicy.php => AssetCheckInPolicy.php} (75%) create mode 100644 app-modules/inventory-management/src/Policies/AssetCheckOutPolicy.php diff --git a/app-modules/inventory-management/config/roles/api/inventory_management.php b/app-modules/inventory-management/config/roles/api/inventory_management.php index 268edc7499..d7c70b0afb 100644 --- a/app-modules/inventory-management/config/roles/api/inventory_management.php +++ b/app-modules/inventory-management/config/roles/api/inventory_management.php @@ -48,6 +48,12 @@ 'asset_type' => [ '*', ], + 'asset_check_in' => [ + '*', + ], + 'asset_check_out' => [ + '*', + ], 'maintenance_activity' => [ '*', ], diff --git a/app-modules/inventory-management/config/roles/web/inventory_management.php b/app-modules/inventory-management/config/roles/web/inventory_management.php index 268edc7499..d7c70b0afb 100644 --- a/app-modules/inventory-management/config/roles/web/inventory_management.php +++ b/app-modules/inventory-management/config/roles/web/inventory_management.php @@ -48,6 +48,12 @@ 'asset_type' => [ '*', ], + 'asset_check_in' => [ + '*', + ], + 'asset_check_out' => [ + '*', + ], 'maintenance_activity' => [ '*', ], diff --git a/app-modules/inventory-management/src/Policies/AssetExchangePolicy.php b/app-modules/inventory-management/src/Policies/AssetCheckInPolicy.php similarity index 75% rename from app-modules/inventory-management/src/Policies/AssetExchangePolicy.php rename to app-modules/inventory-management/src/Policies/AssetCheckInPolicy.php index 031744e4f1..9e57d18e83 100644 --- a/app-modules/inventory-management/src/Policies/AssetExchangePolicy.php +++ b/app-modules/inventory-management/src/Policies/AssetCheckInPolicy.php @@ -38,63 +38,63 @@ use App\Models\Authenticatable; use Illuminate\Auth\Access\Response; -use AdvisingApp\InventoryManagement\Models\AssetExchange; +use AdvisingApp\InventoryManagement\Models\AssetCheckIn; -class AssetExchangePolicy +class AssetCheckInPolicy { public function viewAny(Authenticatable $authenticatable): Response { return $authenticatable->canOrElse( - abilities: 'asset_exchange.view-any', - denyResponse: 'You do not have permission to view asset exchanges.' + abilities: 'asset_check_in.view-any', + denyResponse: 'You do not have permission to view asset check ins.' ); } - public function view(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + public function view(Authenticatable $authenticatable, AssetCheckIn $assetCheckIn): Response { return $authenticatable->canOrElse( - abilities: ['asset_exchange.*.view', "asset_exchange.{$assetExchange->id}.view"], - denyResponse: 'You do not have permission to view this asset exchange.' + abilities: ['asset_check_in.*.view', "asset_check_in.{$assetCheckIn->id}.view"], + denyResponse: 'You do not have permission to view this asset check in.' ); } public function create(Authenticatable $authenticatable): Response { return $authenticatable->canOrElse( - abilities: 'asset_exchange.create', - denyResponse: 'You do not have permission to create asset exchanges.' + abilities: 'asset_check_in.create', + denyResponse: 'You do not have permission to create asset check ins.' ); } - public function update(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + public function update(Authenticatable $authenticatable, AssetCheckIn $assetCheckIn): Response { return $authenticatable->canOrElse( - abilities: ['asset_exchange.*.update', "asset_exchange.{$assetExchange->id}.update"], - denyResponse: 'You do not have permission to update this asset exchange.' + abilities: ['asset_check_in.*.update', "asset_check_in.{$assetCheckIn->id}.update"], + denyResponse: 'You do not have permission to update this asset check in.' ); } - public function delete(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + public function delete(Authenticatable $authenticatable, AssetCheckIn $assetCheckIn): Response { return $authenticatable->canOrElse( - abilities: ['asset_exchange.*.delete', "asset_exchange.{$assetExchange->id}.delete"], - denyResponse: 'You do not have permission to delete this asset exchange.' + abilities: ['asset_check_in.*.delete', "asset_check_in.{$assetCheckIn->id}.delete"], + denyResponse: 'You do not have permission to delete this asset check in.' ); } - public function restore(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + public function restore(Authenticatable $authenticatable, AssetCheckIn $assetCheckIn): Response { return $authenticatable->canOrElse( - abilities: ['asset_exchange.*.restore', "asset_exchange.{$assetExchange->id}.restore"], - denyResponse: 'You do not have permission to restore this asset exchange.' + abilities: ['asset_check_in.*.restore', "asset_check_in.{$assetCheckIn->id}.restore"], + denyResponse: 'You do not have permission to restore this asset check in.' ); } - public function forceDelete(Authenticatable $authenticatable, AssetExchange $assetExchange): Response + public function forceDelete(Authenticatable $authenticatable, AssetCheckIn $assetCheckIn): Response { return $authenticatable->canOrElse( - abilities: ['asset_exchange.*.force-delete', "asset_exchange.{$assetExchange->id}.force-delete"], - denyResponse: 'You do not have permission to permanently delete this asset exchange.' + abilities: ['asset_check_in.*.force-delete', "asset_check_in.{$assetCheckIn->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset check in.' ); } } diff --git a/app-modules/inventory-management/src/Policies/AssetCheckOutPolicy.php b/app-modules/inventory-management/src/Policies/AssetCheckOutPolicy.php new file mode 100644 index 0000000000..cd227de8ca --- /dev/null +++ b/app-modules/inventory-management/src/Policies/AssetCheckOutPolicy.php @@ -0,0 +1,100 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\InventoryManagement\Policies; + +use App\Models\Authenticatable; +use Illuminate\Auth\Access\Response; +use AdvisingApp\InventoryManagement\Models\AssetCheckOut; + +class AssetCheckOutPolicy +{ + public function viewAny(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_check_out.view-any', + denyResponse: 'You do not have permission to view asset check outs.' + ); + } + + public function view(Authenticatable $authenticatable, AssetCheckOut $assetCheckOut): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_check_out.*.view', "asset_check_out.{$assetCheckOut->id}.view"], + denyResponse: 'You do not have permission to view this asset check out.' + ); + } + + public function create(Authenticatable $authenticatable): Response + { + return $authenticatable->canOrElse( + abilities: 'asset_check_out.create', + denyResponse: 'You do not have permission to create asset check outs.' + ); + } + + public function update(Authenticatable $authenticatable, AssetCheckOut $assetCheckOut): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_check_out.*.update', "asset_check_out.{$assetCheckOut->id}.update"], + denyResponse: 'You do not have permission to update this asset check out.' + ); + } + + public function delete(Authenticatable $authenticatable, AssetCheckOut $assetCheckOut): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_check_out.*.delete', "asset_check_out.{$assetCheckOut->id}.delete"], + denyResponse: 'You do not have permission to delete this asset check out.' + ); + } + + public function restore(Authenticatable $authenticatable, AssetCheckOut $assetCheckOut): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_check_out.*.restore', "asset_check_out.{$assetCheckOut->id}.restore"], + denyResponse: 'You do not have permission to restore this asset check out.' + ); + } + + public function forceDelete(Authenticatable $authenticatable, AssetCheckOut $assetCheckOut): Response + { + return $authenticatable->canOrElse( + abilities: ['asset_check_out.*.force-delete', "asset_check_out.{$assetCheckOut->id}.force-delete"], + denyResponse: 'You do not have permission to permanently delete this asset check out.' + ); + } +} From 54e7d5167733ea5174203721e59f4c19f01bcbee Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 08:46:22 -0500 Subject: [PATCH 20/56] Add classification controls to asset status resource. --- .../database/factories/AssetCheckInFactory.php | 6 +++--- .../database/factories/AssetCheckOutFactory.php | 1 - .../AssetStatusResource/Pages/CreateAssetStatus.php | 6 ++++++ .../AssetStatusResource/Pages/ListAssetStatuses.php | 3 +++ .../Resources/AssetStatusResource/Pages/ViewAssetStatus.php | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app-modules/inventory-management/database/factories/AssetCheckInFactory.php b/app-modules/inventory-management/database/factories/AssetCheckInFactory.php index 793d21673d..ec6cf59f3e 100644 --- a/app-modules/inventory-management/database/factories/AssetCheckInFactory.php +++ b/app-modules/inventory-management/database/factories/AssetCheckInFactory.php @@ -16,12 +16,12 @@ class AssetCheckInFactory extends Factory { public function definition(): array { - $checkedOutBy = User::factory()->create(); + $checkedInBy = User::factory()->create(); return [ 'asset_id' => Asset::factory(), - 'checked_in_by_type' => $checkedOutBy->getMorphClass(), - 'checked_in_by_id' => $checkedOutBy->getKey(), + 'checked_in_by_type' => $checkedInBy->getMorphClass(), + 'checked_in_by_id' => $checkedInBy->getKey(), 'checked_in_from_type' => fake()->randomElement([ (new Student())->getMorphClass(), (new Prospect())->getMorphClass(), diff --git a/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php b/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php index f4e1d061c3..f1509098b2 100644 --- a/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php +++ b/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php @@ -21,7 +21,6 @@ public function definition(): array return [ 'asset_id' => Asset::factory(), - // TODO Add variance to this column so that some check outs do not have corresponding check ins 'asset_check_in_id' => null, 'checked_out_by_type' => $checkedOutBy->getMorphClass(), 'checked_out_by_id' => $checkedOutBy->getKey(), diff --git a/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/CreateAssetStatus.php b/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/CreateAssetStatus.php index 8e2facb1c2..62e4601954 100644 --- a/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/CreateAssetStatus.php +++ b/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/CreateAssetStatus.php @@ -37,8 +37,10 @@ namespace AdvisingApp\InventoryManagement\Filament\Resources\AssetStatusResource\Pages; use Filament\Forms\Form; +use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\CreateRecord; +use AdvisingApp\InventoryManagement\Enums\SystemAssetStatusClassification; use AdvisingApp\InventoryManagement\Filament\Resources\AssetStatusResource; class CreateAssetStatus extends CreateRecord @@ -51,6 +53,10 @@ public function form(Form $form): Form ->schema([ TextInput::make('name') ->required(), + Select::make('classification') + ->options(SystemAssetStatusClassification::class) + ->enum(SystemAssetStatusClassification::class) + ->required(), ]); } } diff --git a/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ListAssetStatuses.php b/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ListAssetStatuses.php index a67d22af3f..123fa8d625 100644 --- a/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ListAssetStatuses.php +++ b/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ListAssetStatuses.php @@ -57,6 +57,9 @@ public function table(Table $table): Table TextColumn::make('name') ->searchable() ->sortable(), + TextColumn::make('classification') + ->searchable() + ->sortable(), ]) ->filters([ ]) diff --git a/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ViewAssetStatus.php b/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ViewAssetStatus.php index ed06f374c8..7eb133e489 100644 --- a/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ViewAssetStatus.php +++ b/app-modules/inventory-management/src/Filament/Resources/AssetStatusResource/Pages/ViewAssetStatus.php @@ -54,6 +54,7 @@ public function infolist(Infolist $infolist): Infolist Section::make() ->schema([ TextEntry::make('name'), + TextEntry::make('classification'), ]), ]); } From 627f2d51c6140d3aa723f7da48bbf9f8da49f331 Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 08:59:10 -0500 Subject: [PATCH 21/56] Clean up. --- .../src/Filament/Actions/CheckInAssetHeaderAction.php | 5 +++-- .../src/Filament/Actions/CheckOutAssetHeaderAction.php | 5 +---- app-modules/inventory-management/src/Models/Asset.php | 10 +++++----- .../src/Observers/AssetCheckInObserver.php | 3 --- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php index 2c2b3da131..773cc1a23f 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php @@ -47,14 +47,15 @@ protected function setUp(): void /** @var Asset $asset */ $asset = $this->getRecord(); - if (! $asset->isAvailable()) { + if (! $asset->isCheckedOut()) { $this->failure(); } $asset->checkIns()->create([ 'checked_in_by_type' => auth()->user()?->getMorphClass(), 'checked_in_by_id' => auth()->user()?->id, - // TODO Should we still have this be configurable? Or should the expectation be that this information is the same as the latest check out? + // TODO Should this always simply be the latest check out, or do we want to support + // The possibility that the person checking in is different than whoever checked out? 'checked_in_from_type' => $asset->latestCheckOut->checked_out_to_type, 'checked_in_from_id' => $asset->latestCheckOut->checked_out_to_id, 'notes' => $data['notes'], diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php index 59d59532a7..fe64c51ed2 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php @@ -80,11 +80,8 @@ protected function setUp(): void 'expected_check_in_at' => $data['expected_check_in_at'], ]); - // TODO We may want to move this to an observer in order to clean up... - $checkedOutStatus = AssetStatus::checkedOut()->first(); - $asset->update([ - 'status_id' => $checkedOutStatus->id, + 'status_id' => AssetStatus::checkedOut()->first()->id, ]); $this->success(); diff --git a/app-modules/inventory-management/src/Models/Asset.php b/app-modules/inventory-management/src/Models/Asset.php index 80e673b408..d2723972ea 100644 --- a/app-modules/inventory-management/src/Models/Asset.php +++ b/app-modules/inventory-management/src/Models/Asset.php @@ -88,6 +88,11 @@ public function checkOuts(): HasMany return $this->hasMany(AssetCheckOut::class, 'asset_id'); } + public function checkIns(): HasMany + { + return $this->hasMany(AssetCheckIn::class, 'asset_id'); + } + public function latestCheckOut(): HasOne { return $this->hasOne(AssetCheckOut::class, 'asset_id') @@ -100,11 +105,6 @@ public function latestCheckIn(): HasOne ->latest('checked_in_at'); } - public function checkIns(): HasMany - { - return $this->hasMany(AssetCheckIn::class, 'asset_id'); - } - public function isAvailable(): bool { return $this->status->classification === SystemAssetStatusClassification::Available diff --git a/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php b/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php index 54d9e4fa18..6909116d0b 100644 --- a/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php +++ b/app-modules/inventory-management/src/Observers/AssetCheckInObserver.php @@ -42,9 +42,6 @@ class AssetCheckInObserver { public function created(AssetCheckIn $checkIn): void { - ray('AssetCheckInObserver::created()'); - ray($checkIn->asset->latestCheckOut); - $checkIn->asset->latestCheckOut->update([ 'asset_check_in_id' => $checkIn->id, ]); From 8772bb412eaaf0f88885464cf8d88103602d4570 Mon Sep 17 00:00:00 2001 From: dgoetzit Date: Wed, 3 Jan 2024 14:02:35 +0000 Subject: [PATCH 22/56] chore: fix enforcement of copyright on all files --- .../factories/AssetCheckInFactory.php | 34 +++++++++++++++++++ .../factories/AssetCheckOutFactory.php | 34 +++++++++++++++++++ ...28_174428_create_asset_check_ins_table.php | 34 +++++++++++++++++++ ...8_174437_create_asset_check_outs_table.php | 34 +++++++++++++++++++ .../Actions/CheckInAssetHeaderAction.php | 34 +++++++++++++++++++ .../Actions/CheckOutAssetHeaderAction.php | 34 +++++++++++++++++++ .../src/Models/AssetCheckIn.php | 34 +++++++++++++++++++ .../src/Models/AssetCheckOut.php | 34 +++++++++++++++++++ 8 files changed, 272 insertions(+) diff --git a/app-modules/inventory-management/database/factories/AssetCheckInFactory.php b/app-modules/inventory-management/database/factories/AssetCheckInFactory.php index ec6cf59f3e..aec0066bd4 100644 --- a/app-modules/inventory-management/database/factories/AssetCheckInFactory.php +++ b/app-modules/inventory-management/database/factories/AssetCheckInFactory.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\InventoryManagement\Database\Factories; use App\Models\User; diff --git a/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php b/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php index f1509098b2..908cc3623d 100644 --- a/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php +++ b/app-modules/inventory-management/database/factories/AssetCheckOutFactory.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\InventoryManagement\Database\Factories; use Carbon\Carbon; diff --git a/app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php b/app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php index 08c435f4bb..f837c2993a 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_28_174428_create_asset_check_ins_table.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; diff --git a/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php b/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php index a37094dcd4..4dd77f8ed2 100644 --- a/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php +++ b/app-modules/inventory-management/database/migrations/2023_12_28_174437_create_asset_check_outs_table.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php index 773cc1a23f..9419287ff7 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckInAssetHeaderAction.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\InventoryManagement\Filament\Actions; use Filament\Actions\Action; diff --git a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php index fe64c51ed2..f417c58289 100644 --- a/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php +++ b/app-modules/inventory-management/src/Filament/Actions/CheckOutAssetHeaderAction.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\InventoryManagement\Filament\Actions; use Filament\Forms\Get; diff --git a/app-modules/inventory-management/src/Models/AssetCheckIn.php b/app-modules/inventory-management/src/Models/AssetCheckIn.php index edd1f6dca2..cef99b06aa 100644 --- a/app-modules/inventory-management/src/Models/AssetCheckIn.php +++ b/app-modules/inventory-management/src/Models/AssetCheckIn.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\InventoryManagement\Models; use App\Models\BaseModel; diff --git a/app-modules/inventory-management/src/Models/AssetCheckOut.php b/app-modules/inventory-management/src/Models/AssetCheckOut.php index dad253e8c2..121c9de71b 100644 --- a/app-modules/inventory-management/src/Models/AssetCheckOut.php +++ b/app-modules/inventory-management/src/Models/AssetCheckOut.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\InventoryManagement\Models; use App\Models\BaseModel; From fb54dbe7f508ca92cb933f4e5f6284c9be950403 Mon Sep 17 00:00:00 2001 From: joelicatajr Date: Wed, 3 Jan 2024 14:06:00 +0000 Subject: [PATCH 23/56] chore: fix code style --- .../inventory-management/src/Models/AssetLocation.php | 6 +++--- app-modules/inventory-management/src/Models/AssetType.php | 6 +++--- .../src/Models/MaintenanceActivity.php | 8 ++++---- .../src/Models/ServiceRequestStatus.php | 1 - 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app-modules/inventory-management/src/Models/AssetLocation.php b/app-modules/inventory-management/src/Models/AssetLocation.php index 35e1f96256..871c929e26 100644 --- a/app-modules/inventory-management/src/Models/AssetLocation.php +++ b/app-modules/inventory-management/src/Models/AssetLocation.php @@ -36,11 +36,11 @@ namespace AdvisingApp\InventoryManagement\Models; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; use App\Models\BaseModel; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\SoftDeletes; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\HasMany; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; /** * @mixin IdeHelperAssetLocation diff --git a/app-modules/inventory-management/src/Models/AssetType.php b/app-modules/inventory-management/src/Models/AssetType.php index 1a492ebdfb..692f0dabdc 100644 --- a/app-modules/inventory-management/src/Models/AssetType.php +++ b/app-modules/inventory-management/src/Models/AssetType.php @@ -36,11 +36,11 @@ namespace AdvisingApp\InventoryManagement\Models; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; use App\Models\BaseModel; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\SoftDeletes; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\HasMany; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; /** * @mixin IdeHelperAssetType diff --git a/app-modules/inventory-management/src/Models/MaintenanceActivity.php b/app-modules/inventory-management/src/Models/MaintenanceActivity.php index 6bc1748b66..1e5ec8ce5c 100644 --- a/app-modules/inventory-management/src/Models/MaintenanceActivity.php +++ b/app-modules/inventory-management/src/Models/MaintenanceActivity.php @@ -36,12 +36,12 @@ namespace AdvisingApp\InventoryManagement\Models; -use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; -use AdvisingApp\InventoryManagement\Enums\MaintenanceActivityStatus; use App\Models\BaseModel; -use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\SoftDeletes; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; +use AdvisingApp\InventoryManagement\Enums\MaintenanceActivityStatus; /** * @mixin IdeHelperMaintenanceActivity diff --git a/app-modules/service-management/src/Models/ServiceRequestStatus.php b/app-modules/service-management/src/Models/ServiceRequestStatus.php index 40bd3148b5..5250ece7c4 100644 --- a/app-modules/service-management/src/Models/ServiceRequestStatus.php +++ b/app-modules/service-management/src/Models/ServiceRequestStatus.php @@ -40,7 +40,6 @@ use App\Models\BaseModel; use OwenIt\Auditing\Contracts\Auditable; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Database\Eloquent\Concerns\HasUuids; use Illuminate\Database\Eloquent\Relations\HasMany; use AdvisingApp\ServiceManagement\Enums\ColumnColorOptions; use AdvisingApp\Audit\Models\Concerns\Auditable as AuditableTrait; From 60230e4b538edcac12085a36033419e4ae8e110f Mon Sep 17 00:00:00 2001 From: Derek Goetz Date: Wed, 3 Jan 2024 10:14:25 -0500 Subject: [PATCH 24/56] Remove open search fields and indexing from prospects. --- .../ProspectResource/Pages/ListProspects.php | 14 +++----- app-modules/prospect/src/Models/Prospect.php | 35 ------------------- 2 files changed, 5 insertions(+), 44 deletions(-) diff --git a/app-modules/prospect/src/Filament/Resources/ProspectResource/Pages/ListProspects.php b/app-modules/prospect/src/Filament/Resources/ProspectResource/Pages/ListProspects.php index cc455741c8..a5cc897835 100644 --- a/app-modules/prospect/src/Filament/Resources/ProspectResource/Pages/ListProspects.php +++ b/app-modules/prospect/src/Filament/Resources/ProspectResource/Pages/ListProspects.php @@ -56,7 +56,6 @@ use Filament\Resources\Pages\ListRecords; use Filament\Tables\Filters\SelectFilter; use Illuminate\Database\Eloquent\Builder; -use App\Concerns\FilterTableWithOpenSearch; use Filament\Tables\Actions\BulkActionGroup; use Illuminate\Database\Eloquent\Collection; use Filament\Tables\Actions\DeleteBulkAction; @@ -71,14 +70,11 @@ use AdvisingApp\CareTeam\Filament\Actions\ToggleCareTeamBulkAction; use AdvisingApp\Notification\Filament\Actions\SubscribeTableAction; use AdvisingApp\CaseloadManagement\Actions\TranslateCaseloadFilters; -use App\Filament\Columns\OpenSearch\TextColumn as OpenSearchTextColumn; -use App\Filament\Filters\OpenSearch\SelectFilter as OpenSearchSelectFilter; use AdvisingApp\Engagement\Filament\Actions\Contracts\HasBulkEngagementAction; use AdvisingApp\Engagement\Filament\Actions\Concerns\ImplementsHasBulkEngagementAction; class ListProspects extends ListRecords implements HasBulkEngagementAction { - use FilterTableWithOpenSearch; use ImplementsHasBulkEngagementAction; protected static string $resource = ProspectResource::class; @@ -88,16 +84,16 @@ public function table(Table $table): Table return $table ->columns([ IdColumn::make(), - OpenSearchTextColumn::make(Prospect::displayNameKey()) + TextColumn::make(Prospect::displayNameKey()) ->label('Name') ->searchable() ->sortable(), - OpenSearchTextColumn::make('email') + TextColumn::make('email') ->label('Email') ->translateLabel() ->searchable() ->sortable(), - OpenSearchTextColumn::make('mobile') + TextColumn::make('mobile') ->label('Mobile') ->translateLabel() ->searchable() @@ -147,11 +143,11 @@ public function table(Table $table): Table ->searchable() ->optionsLimit(20) ->query(fn (Builder $query, array $data) => $this->caseloadFilter($query, $data)), - OpenSearchSelectFilter::make('status_id') + SelectFilter::make('status_id') ->relationship('status', 'name') ->multiple() ->preload(), - OpenSearchSelectFilter::make('source_id') + SelectFilter::make('source_id') ->relationship('source', 'name') ->multiple() ->preload(), diff --git a/app-modules/prospect/src/Models/Prospect.php b/app-modules/prospect/src/Models/Prospect.php index 00baff3249..d0aa1a0f80 100644 --- a/app-modules/prospect/src/Models/Prospect.php +++ b/app-modules/prospect/src/Models/Prospect.php @@ -45,7 +45,6 @@ use Illuminate\Notifications\Notifiable; use OwenIt\Auditing\Contracts\Auditable; use AdvisingApp\CareTeam\Models\CareTeam; -use OpenSearch\ScoutDriverPlus\Searchable; use AdvisingApp\Form\Models\FormSubmission; use Illuminate\Database\Eloquent\SoftDeletes; use AdvisingApp\Engagement\Models\EngagementFile; @@ -84,7 +83,6 @@ class Prospect extends BaseModel implements Auditable, Subscribable, Educatable, use HasManyMorphedEngagementResponses; use HasManyMorphedInteractions; use HasSubscriptions; - use Searchable; use NotifiableViaSms; protected $fillable = [ @@ -115,39 +113,6 @@ class Prospect extends BaseModel implements Auditable, Subscribable, Educatable, 'birthdate' => 'date', ]; - public function searchableAs(): string - { - return config('scout.prefix') . 'prospects'; - } - - public function toSearchableArray(): array - { - return [ - 'id' => (int) $this->getScoutKey(), - 'status_id' => $this->status_id, - 'source_id' => $this->source_id, - 'first_name' => $this->first_name, - 'last_name' => $this->last_name, - 'full_name' => $this->full_name, - 'preferred' => $this->preferred, - 'description' => $this->description, - 'email' => $this->email, - 'email_2' => $this->email_2, - 'mobile' => $this->mobile, - 'sms_opt_out' => $this->sms_opt_out, - 'email_bounce' => $this->email_bounce, - 'phone' => $this->phone, - 'address' => $this->address, - 'address_2' => $this->address_2, - 'birthdate' => $this->birthdate, - 'hsgrad' => (int) $this->hsgrad, - 'assigned_to_id' => $this->assigned_to_id, - 'created_by_id' => $this->created_by_id, - 'created_at' => $this->created_at->format('Y-m-d H:i:s'), - 'updated_at' => $this->updated_at->format('Y-m-d H:i:s'), - ]; - } - public function identifier(): string { return $this->id; From 0630c2f3446698ce7cdd049c6ffafa66fba19da6 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 17:51:41 -0500 Subject: [PATCH 25/56] Init event registration Signed-off-by: Kevin Ullyott --- .../src/Models/SubmissibleAuthentication.php | 2 +- ..._create_event_registration_forms_table.php | 60 ++++ ...27_194216_create_event_attendees_table.php | 56 ++++ ...7_create_event_attendee_entities_table.php | 52 ++++ ...te_event_registration_form_steps_table.php | 55 ++++ ...e_event_registration_form_fields_table.php | 58 ++++ ...egistration_form_authentications_table.php | 54 ++++ ...nt_registration_form_submissions_table.php | 59 ++++ ...0_create_survey_field_submission_table.php | 54 ++++ .../src/Enums/EventAttendeeStatus.php | 22 ++ .../EventRegistrationWidgetController.php | 263 ++++++++++++++++++ .../src/Models/EventAttendee.php | 61 ++++ .../src/Models/EventRegistrationForm.php | 89 ++++++ .../EventRegistrationFormAuthentication.php | 61 ++++ .../src/Models/EventRegistrationFormField.php | 71 +++++ .../src/Models/EventRegistrationFormStep.php | 71 +++++ .../EventRegistrationFormSubmission.php | 130 +++++++++ ...icateEventRegistrationFormNotification.php | 70 +++++ .../MeetingCenterServiceProvider.php | 12 + ...survey_roles.php => survey_management.php} | 0 20 files changed, 1299 insertions(+), 1 deletion(-) create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194215_create_event_registration_forms_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194216_create_event_attendees_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194217_create_event_attendee_entities_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194226_create_event_registration_form_steps_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194227_create_event_registration_form_fields_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194228_create_event_registration_form_authentications_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php create mode 100644 app-modules/meeting-center/database/migrations/2023_12_27_194230_create_survey_field_submission_table.php create mode 100644 app-modules/meeting-center/src/Enums/EventAttendeeStatus.php create mode 100644 app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php create mode 100644 app-modules/meeting-center/src/Models/EventAttendee.php create mode 100644 app-modules/meeting-center/src/Models/EventRegistrationForm.php create mode 100644 app-modules/meeting-center/src/Models/EventRegistrationFormAuthentication.php create mode 100644 app-modules/meeting-center/src/Models/EventRegistrationFormField.php create mode 100644 app-modules/meeting-center/src/Models/EventRegistrationFormStep.php create mode 100644 app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php create mode 100644 app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php rename app-modules/survey/config/roles/web/{survey_roles.php => survey_management.php} (100%) diff --git a/app-modules/form/src/Models/SubmissibleAuthentication.php b/app-modules/form/src/Models/SubmissibleAuthentication.php index 9e6c8d5523..b5a0360f6f 100644 --- a/app-modules/form/src/Models/SubmissibleAuthentication.php +++ b/app-modules/form/src/Models/SubmissibleAuthentication.php @@ -66,7 +66,7 @@ public function prunable(): Builder ->where('created_at', '<', now()->subMonth()); } - public function author(): MorphTo + public function author(): MorphTo|BelongsTo { return $this->morphTo(); } diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194215_create_event_registration_forms_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194215_create_event_registration_forms_table.php new file mode 100644 index 0000000000..8571656d00 --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194215_create_event_registration_forms_table.php @@ -0,0 +1,60 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_registration_forms', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete(); + $table->boolean('embed_enabled')->default(false); + $table->json('allowed_domains')->nullable(); + $table->string('primary_color')->nullable(); + $table->string('rounding')->nullable(); + $table->boolean('is_wizard')->default(false); + $table->boolean('recaptcha_enabled')->default(false); + $table->json('content')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194216_create_event_attendees_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194216_create_event_attendees_table.php new file mode 100644 index 0000000000..2bcee55835 --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194216_create_event_attendees_table.php @@ -0,0 +1,56 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_attendees', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->string('status'); + $table->string('email'); + $table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete(); + + $table->timestamps(); + + $table->unique(['email', 'event_id']); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194217_create_event_attendee_entities_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194217_create_event_attendee_entities_table.php new file mode 100644 index 0000000000..45532122f7 --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194217_create_event_attendee_entities_table.php @@ -0,0 +1,52 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_attendees_entities', function (Blueprint $table) { + $table->string('entity_id'); + $table->string('entity_type'); + $table->foreignUuid('event_attendee_id')->constrained('event_attendees')->cascadeOnDelete(); + + $table->unique(['entity_id', 'entity_type', 'event_attendee_id']); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194226_create_event_registration_form_steps_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194226_create_event_registration_form_steps_table.php new file mode 100644 index 0000000000..bae9ad05b1 --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194226_create_event_registration_form_steps_table.php @@ -0,0 +1,55 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_registration_form_steps', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->text('label'); + $table->json('content')->nullable(); + $table->foreignUuid('form_id')->constrained('event_registration_forms')->cascadeOnDelete(); + $table->integer('sort'); + + $table->timestamps(); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194227_create_event_registration_form_fields_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194227_create_event_registration_form_fields_table.php new file mode 100644 index 0000000000..4b8f20c26a --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194227_create_event_registration_form_fields_table.php @@ -0,0 +1,58 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_registration_form_fields', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->text('label'); + $table->text('type'); + $table->boolean('is_required'); + $table->json('config'); + + $table->foreignUuid('form_id')->constrained('event_registration_forms')->cascadeOnDelete(); + $table->foreignUuid('step_id')->nullable()->constrained('event_registration_form_steps')->cascadeOnDelete(); + + $table->timestamps(); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194228_create_event_registration_form_authentications_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194228_create_event_registration_form_authentications_table.php new file mode 100644 index 0000000000..31216c9ba4 --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194228_create_event_registration_form_authentications_table.php @@ -0,0 +1,54 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_registration_form_authentications', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->foreignUuid('event_attendee_id')->constrained('event_attendees')->cascadeOnDelete(); + $table->string('code')->nullable(); + $table->foreignUuid('form_id')->constrained('event_registration_forms')->cascadeOnDelete(); + + $table->timestamps(); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php new file mode 100644 index 0000000000..0165143dbd --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php @@ -0,0 +1,59 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_registration_form_submissions', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->foreignUuid('form_id')->constrained('event_registration_forms')->cascadeOnDelete(); + $table->foreignUuid('event_attendee_id')->constrained('event_attendees')->cascadeOnDelete(); + $table->timestamp('submitted_at')->nullable(); + $table->timestamp('canceled_at')->nullable(); + $table->string('request_method')->nullable(); + $table->text('request_note')->nullable(); + $table->foreignUuid('requester_id')->nullable()->constrained('users')->nullOnDelete(); + + $table->timestamps(); + $table->softDeletes(); + }); + } +}; diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194230_create_survey_field_submission_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194230_create_survey_field_submission_table.php new file mode 100644 index 0000000000..d5b0f6c326 --- /dev/null +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194230_create_survey_field_submission_table.php @@ -0,0 +1,54 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +return new class () extends Migration { + public function up(): void + { + Schema::create('event_registration_form_field_submission', function (Blueprint $table) { + $table->uuid('id')->primary(); + + $table->longText('response'); + $table->foreignUuid('field_id')->constrained('event_registration_form_fields')->cascadeOnDelete(); + $table->foreignUuid('submission_id')->constrained('event_registration_form_submissions')->cascadeOnDelete(); + + $table->timestamps(); + }); + } +}; diff --git a/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php b/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php new file mode 100644 index 0000000000..f84db2a022 --- /dev/null +++ b/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php @@ -0,0 +1,22 @@ + 'Not Attending', + default => $this->name, + }; + } +} diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php new file mode 100644 index 0000000000..39dd56722f --- /dev/null +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -0,0 +1,263 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Http\Controllers; + +use Closure; +use Illuminate\Support\Str; +use Illuminate\Http\Request; +use Illuminate\Http\JsonResponse; +use Filament\Support\Colors\Color; +use Illuminate\Support\Facades\URL; +use App\Http\Controllers\Controller; +use Illuminate\Support\Facades\Hash; +use AdvisingApp\Survey\Models\Survey; +use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\Notification; +use Symfony\Component\HttpFoundation\Response; +use AdvisingApp\Survey\Models\SurveySubmission; +use AdvisingApp\Form\Actions\GenerateFormKitSchema; +use AdvisingApp\MeetingCenter\Models\EventAttendee; +use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; +use AdvisingApp\Form\Actions\GenerateSubmissibleValidation; +use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; +use AdvisingApp\Application\Models\ApplicationAuthentication; +use AdvisingApp\Form\Actions\ResolveSubmissionAuthorFromEmail; +use AdvisingApp\Form\Filament\Blocks\EducatableEmailFormFieldBlock; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; +use AdvisingApp\IntegrationGoogleRecaptcha\Settings\GoogleRecaptchaSettings; +use AdvisingApp\Form\Notifications\AuthenticateEventRegistrationFormNotification; + +class EventRegistrationWidgetController extends Controller +{ + public function view(GenerateFormKitSchema $generateSchema, EventRegistrationForm $form): JsonResponse + { + return response()->json( + [ + 'name' => $form->event->title, + 'description' => $form->event->description, + // TODO: Maybe get rid of this? It would never not be authenticated. + 'is_authenticated' => true, + 'authentication_url' => URL::signedRoute('event-registration.request-authentication', ['form' => $form]), + 'recaptcha_enabled' => $form->recaptcha_enabled, + ...($form->recaptcha_enabled ? [ + 'recaptcha_site_key' => app(GoogleRecaptchaSettings::class)->site_key, + ] : []), + 'schema' => $generateSchema($form), + 'primary_color' => Color::all()[$form->primary_color ?? 'blue'], + 'rounding' => $form->rounding, + ], + ); + } + + public function requestAuthentication(Request $request, EventRegistrationForm $form): JsonResponse + { + $data = $request->validate([ + 'email' => ['required', 'email'], + ]); + + $attendee = EventAttendee::firstOrNew( + [ + 'email' => $data['email'], + 'event_id' => $form->event_id, + ], + ); + + if (empty($attendee->status)) { + $attendee->status = EventAttendeeStatus::Pending; + } + + // TODO: When an EventAttendee is created, we should try and match it to an entity, perhaps in an observer. + $attendee->save(); + + $code = random_int(100000, 999999); + + $authentication = new EventRegistrationFormAuthentication(); + $authentication->author()->associate($attendee); + $authentication->submissible()->associate($form); + $authentication->code = Hash::make($code); + $authentication->save(); + + Notification::route('mail', $attendee->email)->notify(new AuthenticateEventRegistrationFormNotification($authentication, $code)); + + return response()->json([ + 'message' => "We've sent an authentication code to {$attendee->email}.", + 'authentication_url' => URL::signedRoute('event-registration.authenticate', [ + 'form' => $form, + 'authentication' => $authentication, + ]), + ]); + } + + public function authenticate(Request $request, Survey $survey, ApplicationAuthentication $authentication): JsonResponse + { + if ($authentication->isExpired()) { + return response()->json([ + 'is_expired' => true, + ]); + } + + $request->validate([ + 'code' => ['required', 'integer', 'digits:6', function (string $attribute, int $value, Closure $fail) use ($authentication) { + if (Hash::check($value, $authentication->code)) { + return; + } + + $fail('The provided code is invalid.'); + }], + ]); + + return response()->json([ + 'submission_url' => URL::signedRoute('surveys.submit', [ + 'survey' => $authentication, + 'application' => $authentication->submissible, + ]), + ]); + } + + public function store( + Request $request, + GenerateSubmissibleValidation $generateValidation, + ResolveSubmissionAuthorFromEmail $resolveSubmissionAuthorFromEmail, + Survey $survey, + ): JsonResponse { + $authentication = $request->query('authentication'); + + if (filled($authentication)) { + $authentication = ApplicationAuthentication::findOrFail($authentication); + } + + if ( + $survey->is_authenticated && + ($authentication?->isExpired() ?? true) + ) { + abort(Response::HTTP_UNAUTHORIZED); + } + + $validator = Validator::make( + $request->all(), + $generateValidation($survey) + ); + + if ($validator->fails()) { + return response()->json( + [ + 'errors' => (object) $validator->errors(), + ], + Response::HTTP_UNPROCESSABLE_ENTITY + ); + } + + /** @var SurveySubmission $submission */ + $submission = $survey->submissions()->make(); + + if ($authentication) { + $submission->author()->associate($authentication->author); + + $authentication->delete(); + } + + $submission->submitted_at = now(); + + $submission->save(); + + $data = $validator->validated(); + + unset($data['recaptcha-token']); + + if ($survey->is_wizard) { + foreach ($survey->steps as $step) { + $stepFields = $step->fields()->pluck('type', 'id')->all(); + + foreach ($data[$step->label] as $fieldId => $response) { + $submission->fields()->attach( + $fieldId, + ['id' => Str::orderedUuid(), 'response' => $response], + ); + + if ($submission->author) { + continue; + } + + if ($stepFields[$fieldId] !== EducatableEmailFormFieldBlock::type()) { + continue; + } + + $author = $resolveSubmissionAuthorFromEmail($response); + + if (! $author) { + continue; + } + + $submission->author()->associate($author); + } + } + } else { + $surveyFields = $survey->fields()->pluck('type', 'id')->all(); + + foreach ($data as $fieldId => $response) { + $submission->fields()->attach( + $fieldId, + ['id' => Str::orderedUuid(), 'response' => $response], + ); + + if ($submission->author) { + continue; + } + + if ($surveyFields[$fieldId] !== EducatableEmailFormFieldBlock::type()) { + continue; + } + + $author = $resolveSubmissionAuthorFromEmail($response); + + if (! $author) { + continue; + } + + $submission->author()->associate($author); + } + } + + $submission->save(); + + return response()->json( + [ + 'message' => 'Survey submitted successfully.', + ] + ); + } +} diff --git a/app-modules/meeting-center/src/Models/EventAttendee.php b/app-modules/meeting-center/src/Models/EventAttendee.php new file mode 100644 index 0000000000..fab1a5c640 --- /dev/null +++ b/app-modules/meeting-center/src/Models/EventAttendee.php @@ -0,0 +1,61 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Models; + +use App\Models\BaseModel; +use App\Models\Attributes\NoPermissions; +use Illuminate\Notifications\Notifiable; +use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; + +#[NoPermissions] +/** + * @mixin IdeHelperEventAttendee + */ +class EventAttendee extends BaseModel +{ + use Notifiable; + + protected $fillable = [ + 'status', + 'email', + 'event_id', + ]; + + protected $casts = [ + 'status' => EventAttendeeStatus::class, + ]; +} diff --git a/app-modules/meeting-center/src/Models/EventRegistrationForm.php b/app-modules/meeting-center/src/Models/EventRegistrationForm.php new file mode 100644 index 0000000000..672883ea58 --- /dev/null +++ b/app-modules/meeting-center/src/Models/EventRegistrationForm.php @@ -0,0 +1,89 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Models; + +use AdvisingApp\Form\Enums\Rounding; +use AdvisingApp\Form\Models\Submissible; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\BelongsTo; + +/** + * @mixin IdeHelperEventRegistrationForm + */ +class EventRegistrationForm extends Submissible +{ + protected $fillable = [ + 'form_id', + 'embed_enabled', + 'allowed_domains', + 'is_wizard', + 'recaptcha_enabled', + 'primary_color', + 'rounding', + 'content', + ]; + + protected $casts = [ + 'content' => 'array', + 'embed_enabled' => 'boolean', + 'allowed_domains' => 'array', + 'is_wizard' => 'boolean', + 'recaptcha_enabled' => 'boolean', + 'rounding' => Rounding::class, + ]; + + public function event(): BelongsTo + { + return $this + ->belongsTo(Event::class, 'event_id'); + } + + public function fields(): HasMany + { + return $this->hasMany(EventRegistrationFormField::class); + } + + public function steps(): HasMany + { + return $this->hasMany(EventRegistrationFormStep::class); + } + + public function submissions(): HasMany + { + return $this->hasMany(EventRegistrationFormSubmission::class); + } +} diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormAuthentication.php b/app-modules/meeting-center/src/Models/EventRegistrationFormAuthentication.php new file mode 100644 index 0000000000..d312ed5e03 --- /dev/null +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormAuthentication.php @@ -0,0 +1,61 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Models; + +use App\Models\Attributes\NoPermissions; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use AdvisingApp\Form\Models\SubmissibleAuthentication; + +#[NoPermissions] +/** + * @property-read EventRegistrationForm $submissible + * + * @mixin IdeHelperEventRegistrationFormAuthentication + */ +class EventRegistrationFormAuthentication extends SubmissibleAuthentication +{ + public function submissible(): BelongsTo + { + return $this + ->belongsTo(EventRegistrationForm::class, 'form_id'); + } + + public function author(): BelongsTo + { + return $this->belongsTo(EventAttendee::class, 'event_attendee_id'); + } +} diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormField.php b/app-modules/meeting-center/src/Models/EventRegistrationFormField.php new file mode 100644 index 0000000000..7d1867c5c6 --- /dev/null +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormField.php @@ -0,0 +1,71 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Models; + +use AdvisingApp\Form\Models\SubmissibleField; +use Illuminate\Database\Eloquent\Relations\BelongsTo; + +/** + * @mixin IdeHelperEventRegistrationFormField + */ +class EventRegistrationFormField extends SubmissibleField +{ + protected $fillable = [ + 'config', + 'label', + 'type', + 'is_required', + 'form_id', + ]; + + protected $casts = [ + 'config' => 'array', + 'is_required' => 'bool', + ]; + + public function submissible(): BelongsTo + { + return $this + ->belongsTo(EventRegistrationForm::class, 'form_id'); + } + + public function step(): BelongsTo + { + return $this + ->belongsTo(EventRegistrationFormStep::class, 'step_id'); + } +} diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormStep.php b/app-modules/meeting-center/src/Models/EventRegistrationFormStep.php new file mode 100644 index 0000000000..89ed913a0f --- /dev/null +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormStep.php @@ -0,0 +1,71 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Models; + +use App\Models\Attributes\NoPermissions; +use AdvisingApp\Form\Models\SubmissibleStep; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\BelongsTo; + +#[NoPermissions] +/** + * @mixin IdeHelperEventRegistrationFormStep + */ +class EventRegistrationFormStep extends SubmissibleStep +{ + protected $fillable = [ + 'label', + 'content', + 'sort', + ]; + + protected $casts = [ + 'content' => 'array', + 'sort' => 'integer', + ]; + + public function submissible(): BelongsTo + { + return $this + ->belongsTo(EventRegistrationForm::class, 'form_id'); + } + + public function fields(): HasMany + { + return $this->hasMany(EventRegistrationFormField::class, 'step_id'); + } +} diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php new file mode 100644 index 0000000000..4a1392f1ae --- /dev/null +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php @@ -0,0 +1,130 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Models; + +use App\Models\User; +use AdvisingApp\Form\Models\Submission; +use Illuminate\Database\Eloquent\Builder; +use AdvisingApp\Form\Enums\FormSubmissionStatus; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use AdvisingApp\Form\Enums\FormSubmissionRequestDeliveryMethod; + +/** + * @mixin IdeHelperEventRegistrationFormSubmission + */ +class EventRegistrationFormSubmission extends Submission +{ + protected $fillable = [ + 'canceled_at', + 'form_id', + 'request_method', + 'request_note', + 'submitted_at', + ]; + + protected $casts = [ + 'submitted_at' => 'immutable_datetime', + 'canceled_at' => 'immutable_datetime', + 'request_method' => FormSubmissionRequestDeliveryMethod::class, + ]; + + public function submissible(): BelongsTo + { + return $this + ->belongsTo(EventRegistrationForm::class, 'form_id'); + } + + public function requester(): BelongsTo + { + return $this->belongsTo(User::class, 'requester_id'); + } + + public function fields(): BelongsToMany + { + return $this->belongsToMany( + EventRegistrationFormField::class, + 'event_registration_form_field_submission', + 'submission_id', + 'field_id', + ) + ->withPivot(['id', 'response']); + } + + public function deliverRequest(): void + { + $this->request_method->deliver($this); + } + + public function scopeRequested(Builder $query): Builder + { + return $query->notSubmitted()->notCanceled(); + } + + public function scopeSubmitted(Builder $query): Builder + { + return $query->whereNotNull('submitted_at'); + } + + public function scopeCanceled(Builder $query): Builder + { + return $query->notSubmitted()->whereNotNull('canceled_at'); + } + + public function scopeNotSubmitted(Builder $query): Builder + { + return $query->whereNull('submitted_at'); + } + + public function scopeNotCanceled(Builder $query): Builder + { + return $query->whereNull('canceled_at'); + } + + public function getStatus(): FormSubmissionStatus + { + if ($this->submitted_at) { + return FormSubmissionStatus::Submitted; + } + + if ($this->canceled_at) { + return FormSubmissionStatus::Canceled; + } + + return FormSubmissionStatus::Requested; + } +} diff --git a/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php b/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php new file mode 100644 index 0000000000..6719016200 --- /dev/null +++ b/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php @@ -0,0 +1,70 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Form\Notifications; + +use Illuminate\Bus\Queueable; +use Illuminate\Notifications\Notification; +use Illuminate\Notifications\AnonymousNotifiable; +use AdvisingApp\Notification\Notifications\Messages\MailMessage; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; + +class AuthenticateEventRegistrationFormNotification extends Notification +{ + use Queueable; + + public function __construct( + public EventRegistrationFormAuthentication $authentication, + public int $code, + ) {} + + /** + * @return array + */ + public function via(object $notifiable): array + { + return ['mail']; + } + + public function toMail(AnonymousNotifiable $notifiable): MailMessage + { + return MailMessage::make() + ->subject("Your authentication code for {$this->authentication->submissible->event->title} registration") + ->line("Your code is: {$this->code}.") + ->line('You should type this code into the form to authenticate yourself.') + ->line('For security reasons, the code will expire in 24 hours, but you can always request another.'); + } +} diff --git a/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php b/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php index 4da3cd67f1..bc5e36b29c 100644 --- a/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php +++ b/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php @@ -44,10 +44,16 @@ use AdvisingApp\MeetingCenter\Jobs\SyncCalendars; use AdvisingApp\MeetingCenter\MeetingCenterPlugin; use AdvisingApp\MeetingCenter\Models\CalendarEvent; +use AdvisingApp\MeetingCenter\Models\EventAttendee; use Illuminate\Database\Eloquent\Relations\Relation; use AdvisingApp\Authorization\AuthorizationRoleRegistry; +use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; use AdvisingApp\Authorization\AuthorizationPermissionRegistry; use AdvisingApp\MeetingCenter\Observers\CalendarEventObserver; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormField; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormSubmission; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; class MeetingCenterServiceProvider extends ServiceProvider { @@ -62,6 +68,12 @@ public function boot(): void 'calendar' => Calendar::class, 'calendar_event' => CalendarEvent::class, 'event' => Event::class, + 'event_attendee' => EventAttendee::class, + 'event_registration_form' => EventRegistrationForm::class, + 'event_registration_form_authentication' => EventRegistrationFormAuthentication::class, + 'event_registration_form_field' => EventRegistrationFormField::class, + 'event_registration_form_step' => EventRegistrationFormStep::class, + 'event_registration_form_submission' => EventRegistrationFormSubmission::class, ]); $this->callAfterResolving(Schedule::class, function (Schedule $schedule) { diff --git a/app-modules/survey/config/roles/web/survey_roles.php b/app-modules/survey/config/roles/web/survey_management.php similarity index 100% rename from app-modules/survey/config/roles/web/survey_roles.php rename to app-modules/survey/config/roles/web/survey_management.php From 22399e10809b6ac54faa2ccce46e091c32cb6945 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 17:57:07 -0500 Subject: [PATCH 26/56] Fix survey widget auth Signed-off-by: Kevin Ullyott --- .../src/Http/Controllers/SurveyWidgetController.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app-modules/survey/src/Http/Controllers/SurveyWidgetController.php b/app-modules/survey/src/Http/Controllers/SurveyWidgetController.php index 5c8a72a9ef..8a1c815907 100644 --- a/app-modules/survey/src/Http/Controllers/SurveyWidgetController.php +++ b/app-modules/survey/src/Http/Controllers/SurveyWidgetController.php @@ -53,7 +53,6 @@ use AdvisingApp\Form\Actions\GenerateFormKitSchema; use AdvisingApp\Survey\Models\SurveyAuthentication; use AdvisingApp\Form\Actions\GenerateSubmissibleValidation; -use AdvisingApp\Application\Models\ApplicationAuthentication; use AdvisingApp\Form\Actions\ResolveSubmissionAuthorFromEmail; use AdvisingApp\Form\Notifications\AuthenticateFormNotification; use AdvisingApp\Form\Filament\Blocks\EducatableEmailFormFieldBlock; @@ -119,7 +118,7 @@ public function requestAuthentication(Request $request, ResolveSubmissionAuthorF ]); } - public function authenticate(Request $request, Survey $survey, ApplicationAuthentication $authentication): JsonResponse + public function authenticate(Request $request, Survey $survey, SurveyAuthentication $authentication): JsonResponse { if ($authentication->isExpired()) { return response()->json([ @@ -139,8 +138,8 @@ public function authenticate(Request $request, Survey $survey, ApplicationAuthen return response()->json([ 'submission_url' => URL::signedRoute('surveys.submit', [ - 'survey' => $authentication, - 'application' => $authentication->submissible, + 'authentication' => $authentication, + 'survey' => $authentication->submissible, ]), ]); } @@ -154,7 +153,7 @@ public function store( $authentication = $request->query('authentication'); if (filled($authentication)) { - $authentication = ApplicationAuthentication::findOrFail($authentication); + $authentication = SurveyAuthentication::findOrFail($authentication); } if ( From e9f66c41e0ccaf722765b9dc83f319b0550d4105 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 18:07:51 -0500 Subject: [PATCH 27/56] Clear out all non-related code from Event Reg Widget Controller Signed-off-by: Kevin Ullyott --- .../EventRegistrationWidgetController.php | 74 +++++-------------- 1 file changed, 17 insertions(+), 57 deletions(-) diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index 39dd56722f..3bd79a987d 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -44,19 +44,16 @@ use Illuminate\Support\Facades\URL; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Hash; -use AdvisingApp\Survey\Models\Survey; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Notification; use Symfony\Component\HttpFoundation\Response; -use AdvisingApp\Survey\Models\SurveySubmission; use AdvisingApp\Form\Actions\GenerateFormKitSchema; use AdvisingApp\MeetingCenter\Models\EventAttendee; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; use AdvisingApp\Form\Actions\GenerateSubmissibleValidation; use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; -use AdvisingApp\Application\Models\ApplicationAuthentication; use AdvisingApp\Form\Actions\ResolveSubmissionAuthorFromEmail; -use AdvisingApp\Form\Filament\Blocks\EducatableEmailFormFieldBlock; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormSubmission; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; use AdvisingApp\IntegrationGoogleRecaptcha\Settings\GoogleRecaptchaSettings; use AdvisingApp\Form\Notifications\AuthenticateEventRegistrationFormNotification; @@ -122,7 +119,7 @@ public function requestAuthentication(Request $request, EventRegistrationForm $f ]); } - public function authenticate(Request $request, Survey $survey, ApplicationAuthentication $authentication): JsonResponse + public function authenticate(Request $request, EventRegistrationForm $form, EventRegistrationFormAuthentication $authentication): JsonResponse { if ($authentication->isExpired()) { return response()->json([ @@ -141,9 +138,9 @@ public function authenticate(Request $request, Survey $survey, ApplicationAuthen ]); return response()->json([ - 'submission_url' => URL::signedRoute('surveys.submit', [ - 'survey' => $authentication, - 'application' => $authentication->submissible, + 'submission_url' => URL::signedRoute('event-registration.submit', [ + 'authentication' => $authentication, + 'form' => $authentication->submissible, ]), ]); } @@ -152,16 +149,15 @@ public function store( Request $request, GenerateSubmissibleValidation $generateValidation, ResolveSubmissionAuthorFromEmail $resolveSubmissionAuthorFromEmail, - Survey $survey, + EventRegistrationForm $form, ): JsonResponse { $authentication = $request->query('authentication'); if (filled($authentication)) { - $authentication = ApplicationAuthentication::findOrFail($authentication); + $authentication = EventRegistrationFormAuthentication::findOrFail($authentication); } if ( - $survey->is_authenticated && ($authentication?->isExpired() ?? true) ) { abort(Response::HTTP_UNAUTHORIZED); @@ -169,7 +165,7 @@ public function store( $validator = Validator::make( $request->all(), - $generateValidation($survey) + $generateValidation($form) ); if ($validator->fails()) { @@ -181,74 +177,38 @@ public function store( ); } - /** @var SurveySubmission $submission */ - $submission = $survey->submissions()->make(); + /** @var EventRegistrationFormSubmission $submission */ + $submission = $form->submissions()->make(); - if ($authentication) { - $submission->author()->associate($authentication->author); + $submission->author()->associate($authentication->author); - $authentication->delete(); - } + $authentication->delete(); $submission->submitted_at = now(); + // TODO: Adjust the status of the EventAttendee to Attending or Not Attending based on the form submission. + $submission->save(); $data = $validator->validated(); unset($data['recaptcha-token']); - if ($survey->is_wizard) { - foreach ($survey->steps as $step) { - $stepFields = $step->fields()->pluck('type', 'id')->all(); - + if ($form->is_wizard) { + foreach ($form->steps as $step) { foreach ($data[$step->label] as $fieldId => $response) { $submission->fields()->attach( $fieldId, ['id' => Str::orderedUuid(), 'response' => $response], ); - - if ($submission->author) { - continue; - } - - if ($stepFields[$fieldId] !== EducatableEmailFormFieldBlock::type()) { - continue; - } - - $author = $resolveSubmissionAuthorFromEmail($response); - - if (! $author) { - continue; - } - - $submission->author()->associate($author); } } } else { - $surveyFields = $survey->fields()->pluck('type', 'id')->all(); - foreach ($data as $fieldId => $response) { $submission->fields()->attach( $fieldId, ['id' => Str::orderedUuid(), 'response' => $response], ); - - if ($submission->author) { - continue; - } - - if ($surveyFields[$fieldId] !== EducatableEmailFormFieldBlock::type()) { - continue; - } - - $author = $resolveSubmissionAuthorFromEmail($response); - - if (! $author) { - continue; - } - - $submission->author()->associate($author); } } @@ -256,7 +216,7 @@ public function store( return response()->json( [ - 'message' => 'Survey submitted successfully.', + 'message' => 'Event registration submitted successfully.', ] ); } From a308bb3fcd456bc4031f635b7120aab9cbcd69de Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 18:27:41 -0500 Subject: [PATCH 28/56] Setup EventRegistrationForm Controller and relations Signed-off-by: Kevin Ullyott --- .../Actions/GenerateSubmissibleEmbedCode.php | 10 +++ .../render-event-registration-form.blade.php | 42 +++++++++++++ app-modules/meeting-center/routes/api.php | 62 +++++++++++++++++++ app-modules/meeting-center/routes/web.php | 9 +++ .../Livewire/RenderEventRegistrationForm.php | 60 ++++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php create mode 100644 app-modules/meeting-center/routes/api.php create mode 100644 app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php diff --git a/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php b/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php index 41140906d9..ea28b94f01 100644 --- a/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php +++ b/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php @@ -42,6 +42,7 @@ use AdvisingApp\Survey\Models\Survey; use AdvisingApp\Form\Models\Submissible; use AdvisingApp\Application\Models\Application; +use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; class GenerateSubmissibleEmbedCode { @@ -75,6 +76,15 @@ public function handle(Submissible $submissible): string EOD; })(), + EventRegistrationForm::class => (function () use ($submissible) { + $scriptUrl = url('js/widgets/events/advising-app-event-registration-form-widget.js?'); + $formDefinitionUrl = URL::signedRoute('event-registration.define', ['form' => $submissible]); + + return << + + EOD; + })(), default => throw new Exception('Unsupported submissible type.'), }; } diff --git a/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php b/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php new file mode 100644 index 0000000000..26a5435918 --- /dev/null +++ b/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php @@ -0,0 +1,42 @@ +{{-- + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +--}} +@php + use AdvisingApp\Form\Actions\GenerateSubmissibleEmbedCode; +@endphp + +
+
+ {!! resolve(GenerateSubmissibleEmbedCode::class)->handle($this->eventRegistrationForm) !!} +
+
diff --git a/app-modules/meeting-center/routes/api.php b/app-modules/meeting-center/routes/api.php new file mode 100644 index 0000000000..13aa9a6000 --- /dev/null +++ b/app-modules/meeting-center/routes/api.php @@ -0,0 +1,62 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +use AdvisingApp\Form\Http\Middleware\EnsureSubmissibleIsEmbeddableAndAuthorized; +use AdvisingApp\MeetingCenter\Http\Controllers\EventRegistrationWidgetController; + +Route::prefix('api') + ->middleware([ + 'api', + EnsureSubmissibleIsEmbeddableAndAuthorized::class . ':form', + ]) + ->group(function () { + Route::prefix('event-registration') + ->name('event-registration.') + ->group(function () { + Route::get('/{form}', [EventRegistrationWidgetController::class, 'view']) + ->middleware(['signed']) + ->name('define'); + Route::post('/{form}/authenticate/request', [EventRegistrationWidgetController::class, 'requestAuthentication']) + ->middleware(['signed']) + ->name('request-authentication'); + Route::post('/{form}/authenticate/{authentication}', [EventRegistrationWidgetController::class, 'authenticate']) + ->middleware(['signed']) + ->name('authenticate'); + Route::post('/{form}/submit', [EventRegistrationWidgetController::class, 'store']) + ->middleware(['signed']) + ->name('submit'); + }); + }); diff --git a/app-modules/meeting-center/routes/web.php b/app-modules/meeting-center/routes/web.php index 796a4317ab..a55eb2e6f2 100644 --- a/app-modules/meeting-center/routes/web.php +++ b/app-modules/meeting-center/routes/web.php @@ -35,6 +35,7 @@ */ use AdvisingApp\MeetingCenter\Enums\CalendarProvider; +use AdvisingApp\Survey\Livewire\RenderEventRegistrationForm; use AdvisingApp\MeetingCenter\Http\Controllers\GoogleCalendarController; use AdvisingApp\MeetingCenter\Http\Controllers\OutlookCalendarController; @@ -45,3 +46,11 @@ provider_routes(CalendarProvider::Google, GoogleCalendarController::class); provider_routes(CalendarProvider::Outlook, OutlookCalendarController::class); }); + +Route::middleware('web') + ->prefix('event-registration') + ->name('event-registration.') + ->group(function () { + Route::get('/{eventRegistrationForm}/respond', RenderEventRegistrationForm::class) + ->name('show'); + }); diff --git a/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php b/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php new file mode 100644 index 0000000000..fbb4552603 --- /dev/null +++ b/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php @@ -0,0 +1,60 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\Survey\Livewire; + +use Livewire\Component; +use Illuminate\Contracts\View\View; +use Filament\Forms\Contracts\HasForms; +use Filament\Forms\Concerns\InteractsWithForms; +use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; + +class RenderEventRegistrationForm extends Component implements HasForms +{ + use InteractsWithForms; + + public bool $show = true; + + public EventRegistrationForm $eventRegistrationForm; + + public ?array $data = []; + + public function render(): View + { + return view('meeting-center::livewire.render-event-registration-form') + ->title("{$this->eventRegistrationForm->event->title} Registration"); + } +} From 99d0c79d2ef5d0ad23420986512112f885e61321 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 18:37:26 -0500 Subject: [PATCH 29/56] Setup the event registration widget Signed-off-by: Kevin Ullyott --- package.json | 3 +- widgets/event-registration/postcss.config.js | 42 ++ widgets/event-registration/src/App.vue | 358 ++++++++++++++++++ .../event-registration/src/formkit.config.js | 47 +++ widgets/event-registration/src/widget.css | 38 ++ widgets/event-registration/src/widget.js | 62 +++ widgets/event-registration/tailwind.config.js | 39 ++ .../tailwind.config.preset.js | 69 ++++ widgets/event-registration/vite.config.js | 58 +++ 9 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 widgets/event-registration/postcss.config.js create mode 100644 widgets/event-registration/src/App.vue create mode 100644 widgets/event-registration/src/formkit.config.js create mode 100644 widgets/event-registration/src/widget.css create mode 100644 widgets/event-registration/src/widget.js create mode 100644 widgets/event-registration/tailwind.config.js create mode 100644 widgets/event-registration/tailwind.config.preset.js create mode 100644 widgets/event-registration/vite.config.js diff --git a/package.json b/package.json index a189c50282..3b3beb6502 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,11 @@ "build:js-compile": "node ./bin/build.js", "build:filament": "php artisan filament:assets", "build:vite": "vite build", - "build": "npm run build:js-compile && npm run build:vite && npm run build:filament && npm run build:application && npm run build:form && npm run build:survey", "build:application": "(cd widgets/application && vite build)", "build:form": "(cd widgets/form && vite build)", "build:survey": "(cd widgets/survey && vite build)", + "build:event-registration": "(cd widgets/event-registration && vite build)", + "build": "npm run build:js-compile && npm run build:vite && npm run build:filament && npm run build:application && npm run build:form && npm run build:survey && npm run build:event-registration", "api-docs:generate": "export NODE_OPTIONS=--max_old_space_size=4096 && env-cmd spectaql spectaql.yml" }, "devDependencies": { diff --git a/widgets/event-registration/postcss.config.js b/widgets/event-registration/postcss.config.js new file mode 100644 index 0000000000..2f7f96d2ff --- /dev/null +++ b/widgets/event-registration/postcss.config.js @@ -0,0 +1,42 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +export default { + plugins: { + 'tailwindcss/nesting': {}, + tailwindcss: { + config: './tailwind.config.js', + }, + autoprefixer: {}, + }, +} diff --git a/widgets/event-registration/src/App.vue b/widgets/event-registration/src/App.vue new file mode 100644 index 0000000000..78579b05e8 --- /dev/null +++ b/widgets/event-registration/src/App.vue @@ -0,0 +1,358 @@ + + + + diff --git a/widgets/event-registration/src/formkit.config.js b/widgets/event-registration/src/formkit.config.js new file mode 100644 index 0000000000..26e2877b28 --- /dev/null +++ b/widgets/event-registration/src/formkit.config.js @@ -0,0 +1,47 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +import { generateClasses } from '@formkit/themes'; +import { genesisIcons } from '@formkit/icons'; +import theme from '../../form/src/FormKit/theme'; +import inputs from '../../form/src/FormKit/Inputs/index'; + +export default { + icons: { + ...genesisIcons, + }, + inputs, + config: { + classes: generateClasses(theme), + }, +}; diff --git a/widgets/event-registration/src/widget.css b/widgets/event-registration/src/widget.css new file mode 100644 index 0000000000..e896335f42 --- /dev/null +++ b/widgets/event-registration/src/widget.css @@ -0,0 +1,38 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +@import '../../form/src/FormKit/index.css'; + +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/widgets/event-registration/src/widget.js b/widgets/event-registration/src/widget.js new file mode 100644 index 0000000000..53f8f4e47d --- /dev/null +++ b/widgets/event-registration/src/widget.js @@ -0,0 +1,62 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +import { createApp, defineCustomElement, getCurrentInstance, h } from "vue"; +import "./widget.css"; +import App from "./App.vue"; +import { defaultConfig, plugin } from "@formkit/vue"; +import config from "./formkit.config.js"; +import VueSignaturePad from "vue-signature-pad"; + +customElements.define( + 'event-registration-embed', + defineCustomElement({ + setup(props) { + const app = createApp(); + + // install plugins + app.use(plugin, defaultConfig(config)); + + app.use(VueSignaturePad); + + app.config.devtools = true; + + const inst = getCurrentInstance(); + Object.assign(inst.appContext, app._context); + Object.assign(inst.provides, app._context.provides); + + return () => h(App, props); + }, + props: ['url'], + }), +); diff --git a/widgets/event-registration/tailwind.config.js b/widgets/event-registration/tailwind.config.js new file mode 100644 index 0000000000..9ab2129136 --- /dev/null +++ b/widgets/event-registration/tailwind.config.js @@ -0,0 +1,39 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +import preset from './tailwind.config.preset.js'; + +export default { + presets: [preset], + content: ['./src/**/*.vue', './src/FormKit/theme.js'], +}; diff --git a/widgets/event-registration/tailwind.config.preset.js b/widgets/event-registration/tailwind.config.preset.js new file mode 100644 index 0000000000..f65aaf5496 --- /dev/null +++ b/widgets/event-registration/tailwind.config.preset.js @@ -0,0 +1,69 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +import forms from '@tailwindcss/forms'; +import typography from '@tailwindcss/typography'; +import FormKitVariants from '@formkit/themes/tailwindcss'; + +export default { + theme: { + extend: { + colors: { + primary: { + 50: 'rgba(var(--primary-50), )', + 100: 'rgba(var(--primary-100), )', + 200: 'rgba(var(--primary-200), )', + 300: 'rgba(var(--primary-300), )', + 400: 'rgba(var(--primary-400), )', + 500: 'rgba(var(--primary-500), )', + 600: 'rgba(var(--primary-600), )', + 700: 'rgba(var(--primary-700), )', + 800: 'rgba(var(--primary-800), )', + 900: 'rgba(var(--primary-900), )', + 950: 'rgba(var(--primary-950), )', + }, + }, + borderRadius: { + sm: 'var(--rounding-sm)', + DEFAULT: 'var(--rounding)', + md: 'var(--rounding-md)', + lg: 'var(--rounding-lg)', + full: 'var(--rounding-sm)', + }, + fontFamily: { + signature: ['Satisfy', 'cursive'], + }, + }, + }, + plugins: [forms, typography, FormKitVariants], +} diff --git a/widgets/event-registration/vite.config.js b/widgets/event-registration/vite.config.js new file mode 100644 index 0000000000..72ee5f9760 --- /dev/null +++ b/widgets/event-registration/vite.config.js @@ -0,0 +1,58 @@ +/* + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +import { resolve } from "path"; +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; + +export default defineConfig({ + plugins: [vue()], + build: { + manifest: true, + lib: { + entry: resolve(__dirname, 'src/widget.js'), + name: 'AdvisingAppEventRegistrationFormWidget', + fileName: 'advising-app-event-registration-form-widget', + formats: ['es'], + }, + outDir: resolve(__dirname, '../../public/js/widgets/events'), + emptyOutDir: true, + sourcemap: true, + }, + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + }, + }, + define: { 'process.env.NODE_ENV': '"production"' }, +}); From b9d0e76c031dac3cf5479bce812d40b957fa9c9b Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 19:01:41 -0500 Subject: [PATCH 30/56] Fix namespace Signed-off-by: Kevin Ullyott --- app-modules/meeting-center/routes/web.php | 2 +- .../meeting-center/src/Livewire/RenderEventRegistrationForm.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app-modules/meeting-center/routes/web.php b/app-modules/meeting-center/routes/web.php index a55eb2e6f2..d1b6d06442 100644 --- a/app-modules/meeting-center/routes/web.php +++ b/app-modules/meeting-center/routes/web.php @@ -35,7 +35,7 @@ */ use AdvisingApp\MeetingCenter\Enums\CalendarProvider; -use AdvisingApp\Survey\Livewire\RenderEventRegistrationForm; +use AdvisingApp\MeetingCenter\Livewire\RenderEventRegistrationForm; use AdvisingApp\MeetingCenter\Http\Controllers\GoogleCalendarController; use AdvisingApp\MeetingCenter\Http\Controllers\OutlookCalendarController; diff --git a/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php b/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php index fbb4552603..60dc4d9cdf 100644 --- a/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php +++ b/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php @@ -34,7 +34,7 @@ */ -namespace AdvisingApp\Survey\Livewire; +namespace AdvisingApp\MeetingCenter\Livewire; use Livewire\Component; use Illuminate\Contracts\View\View; From a5fe53ba9daa581e1ca3ad9f152958fd18b0316b Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 19:44:35 -0500 Subject: [PATCH 31/56] Start adding the ability to add a Form to the Event edit page Signed-off-by: Kevin Ullyott --- .../EventResource/Pages/EditEvent.php | 186 +++++++++++ .../meeting-center/src/Models/Event.php | 6 + .../src/Models/EventRegistrationForm.php | 6 +- composer.json | 2 +- composer.lock | 288 ++++++++---------- 5 files changed, 323 insertions(+), 165 deletions(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php index 7a1ac857ca..cda81e3d39 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php @@ -37,14 +37,33 @@ namespace AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages; use App\Models\User; +use Filament\Forms\Get; use Filament\Forms\Form; use Filament\Actions\ViewAction; use Filament\Actions\DeleteAction; +use Filament\Forms\Components\Grid; +use AdvisingApp\Form\Enums\Rounding; +use AdvisingApp\Form\Rules\IsDomain; +use App\Forms\Components\ColorSelect; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\Toggle; +use Filament\Forms\Components\Section; +use FilamentTiptapEditor\TiptapEditor; +use Filament\Forms\Components\Fieldset; +use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\EditRecord; +use AdvisingApp\MeetingCenter\Models\Event; +use FilamentTiptapEditor\Enums\TiptapOutput; use Filament\Forms\Components\DateTimePicker; +use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; +use AdvisingApp\Form\Filament\Blocks\FormFieldBlockRegistry; +use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep; +use AdvisingApp\MeetingCenter\Models\EventRegistrationFormField; class EditEvent extends EditRecord { @@ -75,9 +94,176 @@ public function form(Form $form): Form DateTimePicker::make('ends_at') ->timezone($user->timezone) ->required(), + Fieldset::make('Registration Form') + ->relationship('eventRegistrationForm') + ->schema([ + Grid::make() + ->schema([ + Toggle::make('embed_enabled') + ->label('Embed Enabled') + ->live() + ->helperText('If enabled, this form can be embedded on other websites.'), + TagsInput::make('allowed_domains') + ->label('Allowed Domains') + ->helperText('Only these domains will be allowed to embed this form.') + ->placeholder('example.com') + ->hidden(fn (Get $get) => ! $get('embed_enabled')) + ->disabled(fn (Get $get) => ! $get('embed_enabled')) + ->nestedRecursiveRules( + [ + 'string', + new IsDomain(), + ] + ), + ]) + ->columnSpanFull(), + Toggle::make('is_wizard') + ->label('Multi-step form') + ->live() + ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()), + Section::make('Fields') + ->schema([ + $this->fieldBuilder(), + ]) + ->hidden(fn (Get $get) => $get('is_wizard')) + ->disabled(fn (?EventRegistrationForm $record) => $record->submissions()->exists()), + Repeater::make('steps') + ->schema([ + TextInput::make('label') + ->required() + ->string() + ->maxLength(255) + ->autocomplete(false) + ->columnSpanFull() + ->lazy(), + $this->fieldBuilder(), + ]) + ->addActionLabel('New step') + ->itemLabel(fn (array $state): ?string => $state['label'] ?? null) + ->visible(fn (Get $get) => $get('is_wizard')) + ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()) + ->relationship() + ->reorderable() + ->columnSpanFull(), + Section::make('Appearance') + ->schema([ + ColorSelect::make('primary_color'), + Select::make('rounding') + ->options(Rounding::class), + ]) + ->columns(), + ]), ]); } + public function fieldBuilder(): TiptapEditor + { + return TiptapEditor::make('content') + ->output(TiptapOutput::Json) + ->blocks(FormFieldBlockRegistry::get()) + ->tools(['bold', 'italic', 'small', '|', 'heading', 'bullet-list', 'ordered-list', 'hr', '|', 'link', 'grid', 'blocks']) + ->placeholder('Drag blocks here to build your form') + ->hiddenLabel() + ->saveRelationshipsUsing(function (TiptapEditor $component, EventRegistrationForm | EventRegistrationFormStep $record) { + if ($component->isDisabled()) { + return; + } + + $form = $record instanceof EventRegistrationForm ? $record : $record->submissible; + $formStep = $record instanceof EventRegistrationFormStep ? $record : null; + + EventRegistrationFormStep::query() + ->whereBelongsTo($form, 'submissible') + ->when($formStep, fn (EloquentBuilder $query) => $query->whereBelongsTo($formStep, 'step')) + ->delete(); + + $content = $component->decodeBlocksBeforeSave($component->getJSON(decoded: true)); + $content['content'] = $this->saveFieldsFromComponents( + $form, + $content['content'] ?? [], + $formStep, + ); + + $record->content = $content; + $record->save(); + }) + ->dehydrated(false) + ->columnSpanFull() + ->extraInputAttributes(['style' => 'min-height: 12rem;']); + } + + public function saveFieldsFromComponents(EventRegistrationForm $form, array $components, ?EventRegistrationFormStep $eventRegistrationFormStep): array + { + foreach ($components as $componentKey => $component) { + if (array_key_exists('content', $component)) { + $components[$componentKey]['content'] = $this->saveFieldsFromComponents($form, $component['content'], $eventRegistrationFormStep); + + continue; + } + + if ($component['type'] !== 'tiptapBlock') { + continue; + } + + $componentAttributes = $component['attrs'] ?? []; + + if (array_key_exists('id', $componentAttributes)) { + $id = $componentAttributes['id'] ?? null; + unset($componentAttributes['id']); + } + + if (array_key_exists('label', $componentAttributes['data'])) { + $label = $componentAttributes['data']['label'] ?? null; + unset($componentAttributes['data']['label']); + } + + if (array_key_exists('isRequired', $componentAttributes['data'])) { + $isRequired = $componentAttributes['data']['isRequired'] ?? null; + unset($componentAttributes['data']['isRequired']); + } + + /** @var EventRegistrationFormField $field */ + $field = $form->fields()->findOrNew($id ?? null); + $field->step()->associate($eventRegistrationFormStep); + $field->label = $label ?? $componentAttributes['type']; + $field->is_required = $isRequired ?? false; + $field->type = $componentAttributes['type']; + $field->config = $componentAttributes['data']; + $field->save(); + + $components[$componentKey]['attrs']['id'] = $field->id; + } + + return $components; + } + + protected function afterCreate(): void + { + $this->clearFormContentForWizard(); + } + + protected function afterSave(): void + { + $this->clearFormContentForWizard(); + } + + protected function clearFormContentForWizard(): void + { + /** @var Event $event */ + $event = $this->record; + + $form = $event->eventRegistrationForm; + + if ($form->is_wizard) { + $form->content = null; + $form->save(); + + return; + } + + $form->steps()->delete(); + } + protected function getHeaderActions(): array { return [ diff --git a/app-modules/meeting-center/src/Models/Event.php b/app-modules/meeting-center/src/Models/Event.php index 6484c5341e..e19a7706e9 100644 --- a/app-modules/meeting-center/src/Models/Event.php +++ b/app-modules/meeting-center/src/Models/Event.php @@ -37,6 +37,7 @@ namespace AdvisingApp\MeetingCenter\Models; use App\Models\BaseModel; +use Illuminate\Database\Eloquent\Relations\HasOne; /** * @mixin IdeHelperEvent @@ -56,4 +57,9 @@ class Event extends BaseModel 'starts_at' => 'datetime', 'ends_at' => 'datetime', ]; + + public function eventRegistrationForm(): HasOne + { + return $this->hasOne(EventRegistrationForm::class, 'event_id'); + } } diff --git a/app-modules/meeting-center/src/Models/EventRegistrationForm.php b/app-modules/meeting-center/src/Models/EventRegistrationForm.php index 672883ea58..e8ed9f9aa2 100644 --- a/app-modules/meeting-center/src/Models/EventRegistrationForm.php +++ b/app-modules/meeting-center/src/Models/EventRegistrationForm.php @@ -74,16 +74,16 @@ public function event(): BelongsTo public function fields(): HasMany { - return $this->hasMany(EventRegistrationFormField::class); + return $this->hasMany(EventRegistrationFormField::class, 'form_id'); } public function steps(): HasMany { - return $this->hasMany(EventRegistrationFormStep::class); + return $this->hasMany(EventRegistrationFormStep::class, 'form_id'); } public function submissions(): HasMany { - return $this->hasMany(EventRegistrationFormSubmission::class); + return $this->hasMany(EventRegistrationFormSubmission::class, 'form_id'); } } diff --git a/composer.json b/composer.json index 9ac9e26dce..97e808d8fb 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "php": "8.2.*", "ext-gd": "*", "ext-pdo": "*", - "awcodes/filament-tiptap-editor": "^3.2.14", + "awcodes/filament-tiptap-editor": "^3.2.17", "aws/aws-php-sns-message-validator": "^1.8.0", "aws/aws-sdk-php": "^3.293", "barryvdh/laravel-debugbar": "^3.9", diff --git a/composer.lock b/composer.lock index 7f43c3aa26..2377067c69 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": "4135a59df44c5333303e7a1b6f1ff947", + "content-hash": "a7c988d45a8bf04ea377069a6dd7b23a", "packages": [ { "name": "amphp/amp", @@ -559,16 +559,16 @@ }, { "name": "awcodes/filament-tiptap-editor", - "version": "v3.2.18", + "version": "v3.2.17", "source": { "type": "git", "url": "https://github.com/awcodes/filament-tiptap-editor.git", - "reference": "7de016e723ba62908f979a39204955e1801b0967" + "reference": "0c56c96d6dddad9b61ad36aaa500cdb04dd5dd9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/awcodes/filament-tiptap-editor/zipball/7de016e723ba62908f979a39204955e1801b0967", - "reference": "7de016e723ba62908f979a39204955e1801b0967", + "url": "https://api.github.com/repos/awcodes/filament-tiptap-editor/zipball/0c56c96d6dddad9b61ad36aaa500cdb04dd5dd9f", + "reference": "0c56c96d6dddad9b61ad36aaa500cdb04dd5dd9f", "shasum": "" }, "require": { @@ -630,7 +630,7 @@ ], "support": { "issues": "https://github.com/awcodes/filament-tiptap-editor/issues", - "source": "https://github.com/awcodes/filament-tiptap-editor/tree/v3.2.18" + "source": "https://github.com/awcodes/filament-tiptap-editor/tree/v3.2.17" }, "funding": [ { @@ -638,7 +638,7 @@ "type": "github" } ], - "time": "2023-12-28T20:05:06+00:00" + "time": "2023-12-27T19:10:56+00:00" }, { "name": "aws/aws-crt-php", @@ -755,16 +755,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.295.3", + "version": "3.294.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "3346f60c6c5075453f90f703693f764dad76a3a8" + "reference": "2e34d45e970c77775e4c298e08732d64b647c41c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3346f60c6c5075453f90f703693f764dad76a3a8", - "reference": "3346f60c6c5075453f90f703693f764dad76a3a8", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2e34d45e970c77775e4c298e08732d64b647c41c", + "reference": "2e34d45e970c77775e4c298e08732d64b647c41c", "shasum": "" }, "require": { @@ -844,9 +844,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.295.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.294.5" }, - "time": "2023-12-28T19:32:33+00:00" + "time": "2023-12-21T19:10:21+00:00" }, { "name": "barryvdh/laravel-debugbar", @@ -2379,41 +2379,6 @@ "relative": true } }, - { - "name": "canyon-gbs/inventory-management", - "version": "1.0", - "dist": { - "type": "path", - "url": "app-modules/inventory-management", - "reference": "16210c789f3a6d5a4b14ce0db3a17f5cdc4f6e48" - }, - "require": { - "filament/filament": "^3.0.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "AdvisingApp\\InventoryManagement\\Providers\\InventoryManagementServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "AdvisingApp\\InventoryManagement\\": "src/", - "AdvisingApp\\InventoryManagement\\Tests\\": "tests/", - "AdvisingApp\\InventoryManagement\\Database\\Factories\\": "database/factories/", - "AdvisingApp\\InventoryManagement\\Database\\Seeders\\": "database/seeders/" - } - }, - "license": [ - "proprietary" - ], - "transport-options": { - "symlink": true, - "relative": true - } - }, { "name": "carbonphp/carbon-doctrine-types", "version": "2.1.0", @@ -4106,16 +4071,16 @@ }, { "name": "filament/actions", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", - "reference": "8f2a3df7c607a24c2433a3a71cb27b20a8dea203" + "reference": "be3a8c110aa69f3f4856816eefd477b600bc06e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/actions/zipball/8f2a3df7c607a24c2433a3a71cb27b20a8dea203", - "reference": "8f2a3df7c607a24c2433a3a71cb27b20a8dea203", + "url": "https://api.github.com/repos/filamentphp/actions/zipball/be3a8c110aa69f3f4856816eefd477b600bc06e2", + "reference": "be3a8c110aa69f3f4856816eefd477b600bc06e2", "shasum": "" }, "require": { @@ -4153,20 +4118,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T15:54:29+00:00" + "time": "2023-12-21T12:38:03+00:00" }, { "name": "filament/filament", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "ae12dc49094560188a4289778a54773045880e44" + "reference": "e1aa070483c2eaa5bb92ce8d959779a9558fe022" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/ae12dc49094560188a4289778a54773045880e44", - "reference": "ae12dc49094560188a4289778a54773045880e44", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/e1aa070483c2eaa5bb92ce8d959779a9558fe022", + "reference": "e1aa070483c2eaa5bb92ce8d959779a9558fe022", "shasum": "" }, "require": { @@ -4218,20 +4183,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T15:54:35+00:00" + "time": "2023-12-22T14:36:15+00:00" }, { "name": "filament/forms", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "26e177a4b3a8ef7b8326d992bb5073f02220a506" + "reference": "673689bd958797b05127fe9956eafeed555b91bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/26e177a4b3a8ef7b8326d992bb5073f02220a506", - "reference": "26e177a4b3a8ef7b8326d992bb5073f02220a506", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/673689bd958797b05127fe9956eafeed555b91bd", + "reference": "673689bd958797b05127fe9956eafeed555b91bd", "shasum": "" }, "require": { @@ -4274,20 +4239,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T15:54:30+00:00" + "time": "2023-12-22T14:36:00+00:00" }, { "name": "filament/infolists", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", - "reference": "66d69c06dbcf74a72dd3a435eda27b1e5e11eaf3" + "reference": "9207c2b83ba9c8dcbcac9a930e93ce87f381d780" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/infolists/zipball/66d69c06dbcf74a72dd3a435eda27b1e5e11eaf3", - "reference": "66d69c06dbcf74a72dd3a435eda27b1e5e11eaf3", + "url": "https://api.github.com/repos/filamentphp/infolists/zipball/9207c2b83ba9c8dcbcac9a930e93ce87f381d780", + "reference": "9207c2b83ba9c8dcbcac9a930e93ce87f381d780", "shasum": "" }, "require": { @@ -4325,20 +4290,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-26T22:39:20+00:00" + "time": "2023-12-22T14:36:00+00:00" }, { "name": "filament/notifications", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", - "reference": "4f5634f9df312050efa3a035c543add6cec0e3a2" + "reference": "5b9255c0793751534461cace12febdc0d4cc05bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/notifications/zipball/4f5634f9df312050efa3a035c543add6cec0e3a2", - "reference": "4f5634f9df312050efa3a035c543add6cec0e3a2", + "url": "https://api.github.com/repos/filamentphp/notifications/zipball/5b9255c0793751534461cace12febdc0d4cc05bb", + "reference": "5b9255c0793751534461cace12febdc0d4cc05bb", "shasum": "" }, "require": { @@ -4377,11 +4342,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T15:54:27+00:00" + "time": "2023-12-17T22:25:42+00:00" }, { "name": "filament/spatie-laravel-media-library-plugin", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-media-library-plugin.git", @@ -4418,16 +4383,16 @@ }, { "name": "filament/spatie-laravel-settings-plugin", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-settings-plugin.git", - "reference": "d26f397a845934462d511432ba88363f63a7e203" + "reference": "7119f3f714dfa0ce098cd90aa2a741147a5508f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/spatie-laravel-settings-plugin/zipball/d26f397a845934462d511432ba88363f63a7e203", - "reference": "d26f397a845934462d511432ba88363f63a7e203", + "url": "https://api.github.com/repos/filamentphp/spatie-laravel-settings-plugin/zipball/7119f3f714dfa0ce098cd90aa2a741147a5508f6", + "reference": "7119f3f714dfa0ce098cd90aa2a741147a5508f6", "shasum": "" }, "require": { @@ -4461,20 +4426,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-26T22:39:37+00:00" + "time": "2023-12-19T13:24:28+00:00" }, { "name": "filament/support", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "97792dad038a87b7a6bfe465c4f1913252c99017" + "reference": "f00f44dd79e8e1b3f92dea6e2ef6e1ba9e5396dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/97792dad038a87b7a6bfe465c4f1913252c99017", - "reference": "97792dad038a87b7a6bfe465c4f1913252c99017", + "url": "https://api.github.com/repos/filamentphp/support/zipball/f00f44dd79e8e1b3f92dea6e2ef6e1ba9e5396dd", + "reference": "f00f44dd79e8e1b3f92dea6e2ef6e1ba9e5396dd", "shasum": "" }, "require": { @@ -4518,20 +4483,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-24T21:16:58+00:00" + "time": "2023-12-22T14:36:21+00:00" }, { "name": "filament/tables", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "e0701467097f6a82b235ad9f31e3c30ae1035118" + "reference": "3391bd1015bdde8e454d0a6391952dc131fb8dad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/e0701467097f6a82b235ad9f31e3c30ae1035118", - "reference": "e0701467097f6a82b235ad9f31e3c30ae1035118", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/3391bd1015bdde8e454d0a6391952dc131fb8dad", + "reference": "3391bd1015bdde8e454d0a6391952dc131fb8dad", "shasum": "" }, "require": { @@ -4571,20 +4536,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T17:31:59+00:00" + "time": "2023-12-22T14:36:23+00:00" }, { "name": "filament/widgets", - "version": "v3.1.31", + "version": "v3.1.27", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", - "reference": "26240d5f7d6aec4dd9c5987880b4deb5f9000ddd" + "reference": "290184b9dfb99436df94a9a0b8511b21811d9e64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/widgets/zipball/26240d5f7d6aec4dd9c5987880b4deb5f9000ddd", - "reference": "26240d5f7d6aec4dd9c5987880b4deb5f9000ddd", + "url": "https://api.github.com/repos/filamentphp/widgets/zipball/290184b9dfb99436df94a9a0b8511b21811d9e64", + "reference": "290184b9dfb99436df94a9a0b8511b21811d9e64", "shasum": "" }, "require": { @@ -4615,7 +4580,7 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T17:31:57+00:00" + "time": "2023-12-17T22:26:03+00:00" }, { "name": "firebase/php-jwt", @@ -5189,16 +5154,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.329.0", + "version": "v0.328.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "3216fd1b6ba33c5f6658c3581e9723ff21d9acb7" + "reference": "211ba786d30a4ab21e012d2b7dbefc49b4fc6a3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/3216fd1b6ba33c5f6658c3581e9723ff21d9acb7", - "reference": "3216fd1b6ba33c5f6658c3581e9723ff21d9acb7", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/211ba786d30a4ab21e012d2b7dbefc49b4fc6a3d", + "reference": "211ba786d30a4ab21e012d2b7dbefc49b4fc6a3d", "shasum": "" }, "require": { @@ -5227,9 +5192,9 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.329.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.328.0" }, - "time": "2023-12-24T01:02:15+00:00" + "time": "2023-12-18T01:00:18+00:00" }, { "name": "google/auth", @@ -6217,16 +6182,16 @@ }, { "name": "laravel/framework", - "version": "v10.39.0", + "version": "v10.38.2", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "114926b07bfb5fbf2545c03aa2ce5c8c37be650c" + "reference": "43da808391da3540d44a8dfeb4e46da4ad8f5723" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/114926b07bfb5fbf2545c03aa2ce5c8c37be650c", - "reference": "114926b07bfb5fbf2545c03aa2ce5c8c37be650c", + "url": "https://api.github.com/repos/laravel/framework/zipball/43da808391da3540d44a8dfeb4e46da4ad8f5723", + "reference": "43da808391da3540d44a8dfeb4e46da4ad8f5723", "shasum": "" }, "require": { @@ -6329,7 +6294,7 @@ "league/flysystem-sftp-v3": "^3.0", "mockery/mockery": "^1.5.1", "nyholm/psr7": "^1.2", - "orchestra/testbench-core": "^8.18", + "orchestra/testbench-core": "^8.15.1", "pda/pheanstalk": "^4.0", "phpstan/phpstan": "^1.4.7", "phpunit/phpunit": "^10.0.7", @@ -6418,20 +6383,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-12-27T14:26:28+00:00" + "time": "2023-12-22T14:39:10+00:00" }, { "name": "laravel/prompts", - "version": "v0.1.14", + "version": "v0.1.13", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "2219fa9c4b944add1e825c3bdb8ecae8bc503bc6" + "reference": "e1379d8ead15edd6cc4369c22274345982edc95a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/2219fa9c4b944add1e825c3bdb8ecae8bc503bc6", - "reference": "2219fa9c4b944add1e825c3bdb8ecae8bc503bc6", + "url": "https://api.github.com/repos/laravel/prompts/zipball/e1379d8ead15edd6cc4369c22274345982edc95a", + "reference": "e1379d8ead15edd6cc4369c22274345982edc95a", "shasum": "" }, "require": { @@ -6447,7 +6412,7 @@ "require-dev": { "mockery/mockery": "^1.5", "pestphp/pest": "^2.3", - "phpstan/phpstan": "^1.11", + "phpstan/phpstan": "^1.10", "phpstan/phpstan-mockery": "^1.1" }, "suggest": { @@ -6473,22 +6438,22 @@ ], "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.14" + "source": "https://github.com/laravel/prompts/tree/v0.1.13" }, - "time": "2023-12-27T04:18:09+00:00" + "time": "2023-10-27T13:53:59+00:00" }, { "name": "laravel/sanctum", - "version": "v3.3.3", + "version": "v3.3.2", "source": { "type": "git", "url": "https://github.com/laravel/sanctum.git", - "reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5" + "reference": "e1a272893bec13cf135627f7e156030b3afe1e60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/8c104366459739f3ada0e994bcd3e6fd681ce3d5", - "reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/e1a272893bec13cf135627f7e156030b3afe1e60", + "reference": "e1a272893bec13cf135627f7e156030b3afe1e60", "shasum": "" }, "require": { @@ -6541,7 +6506,7 @@ "issues": "https://github.com/laravel/sanctum/issues", "source": "https://github.com/laravel/sanctum" }, - "time": "2023-12-19T18:44:48+00:00" + "time": "2023-11-03T13:42:14+00:00" }, { "name": "laravel/scout", @@ -12949,16 +12914,16 @@ }, { "name": "spatie/temporary-directory", - "version": "2.2.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/spatie/temporary-directory.git", - "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a" + "reference": "efc258c9f4da28f0c7661765b8393e4ccee3d19c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a", - "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/efc258c9f4da28f0c7661765b8393e4ccee3d19c", + "reference": "efc258c9f4da28f0c7661765b8393e4ccee3d19c", "shasum": "" }, "require": { @@ -12994,7 +12959,7 @@ ], "support": { "issues": "https://github.com/spatie/temporary-directory/issues", - "source": "https://github.com/spatie/temporary-directory/tree/2.2.1" + "source": "https://github.com/spatie/temporary-directory/tree/2.2.0" }, "funding": [ { @@ -13006,7 +12971,7 @@ "type": "github" } ], - "time": "2023-12-25T11:46:58+00:00" + "time": "2023-09-25T07:13:36+00:00" }, { "name": "sqids/sqids", @@ -15521,21 +15486,21 @@ }, { "name": "symfony/service-contracts", - "version": "v3.4.1", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" + "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838", + "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -15583,7 +15548,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.4.0" }, "funding": [ { @@ -15599,7 +15564,7 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2023-07-30T20:28:31+00:00" }, { "name": "symfony/string", @@ -15784,16 +15749,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.4.1", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "06450585bf65e978026bda220cdebca3f867fde7" + "reference": "dee0c6e5b4c07ce851b462530088e64b255ac9c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7", - "reference": "06450585bf65e978026bda220cdebca3f867fde7", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/dee0c6e5b4c07ce851b462530088e64b255ac9c5", + "reference": "dee0c6e5b4c07ce851b462530088e64b255ac9c5", "shasum": "" }, "require": { @@ -15842,7 +15807,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.4.0" }, "funding": [ { @@ -15858,7 +15823,7 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2023-07-25T15:08:44+00:00" }, { "name": "symfony/uid", @@ -17183,16 +17148,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.43.0", + "version": "v3.41.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "39b5632c39ca9deb4eb7e670ba96fcf5c3a72e3c" + "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/39b5632c39ca9deb4eb7e670ba96fcf5c3a72e3c", - "reference": "39b5632c39ca9deb4eb7e670ba96fcf5c3a72e3c", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8b6ae8dcbaf23f09680643ab832a4a3a260265f6", + "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6", "shasum": "" }, "require": { @@ -17222,7 +17187,8 @@ "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", - "phpunit/phpunit": "^9.6 || ^10.5.5", + "phpunit/phpunit": "^9.6", + "symfony/phpunit-bridge": "^6.3.8 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { @@ -17261,7 +17227,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.43.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.41.1" }, "funding": [ { @@ -17269,7 +17235,7 @@ "type": "github" } ], - "time": "2023-12-28T17:36:39+00:00" + "time": "2023-12-10T19:59:27+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -17787,36 +17753,36 @@ }, { "name": "pestphp/pest", - "version": "v2.30.0", + "version": "v2.28.1", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "97dc32f9d24b84dd071d9e89438a19e43c833f6f" + "reference": "9ee41910201ef8fc5f5b6d1390e5ec4558222927" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/97dc32f9d24b84dd071d9e89438a19e43c833f6f", - "reference": "97dc32f9d24b84dd071d9e89438a19e43c833f6f", + "url": "https://api.github.com/repos/pestphp/pest/zipball/9ee41910201ef8fc5f5b6d1390e5ec4558222927", + "reference": "9ee41910201ef8fc5f5b6d1390e5ec4558222927", "shasum": "" }, "require": { "brianium/paratest": "^7.3.1", - "nunomaduro/collision": "^7.10.0|^8.0.1", + "nunomaduro/collision": "^7.10.0|^8.0.0", "nunomaduro/termwind": "^1.15.1|^2.0.0", "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.5.0", "php": "^8.1.0", - "phpunit/phpunit": "^10.5.5" + "phpunit/phpunit": "^10.5.3" }, "conflict": { - "phpunit/phpunit": ">10.5.5", + "phpunit/phpunit": ">10.5.3", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, "require-dev": { "pestphp/pest-dev-tools": "^2.16.0", - "pestphp/pest-plugin-type-coverage": "^2.6.0", - "symfony/process": "^6.4.0|^7.0.0" + "pestphp/pest-plugin-type-coverage": "^2.5.0", + "symfony/process": "^6.4.0|^7.0.1" }, "bin": [ "bin/pest" @@ -17879,7 +17845,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.30.0" + "source": "https://github.com/pestphp/pest/tree/v2.28.1" }, "funding": [ { @@ -17891,7 +17857,7 @@ "type": "github" } ], - "time": "2023-12-28T10:36:40+00:00" + "time": "2023-12-15T11:42:34+00:00" }, { "name": "pestphp/pest-plugin", @@ -18874,16 +18840,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.5", + "version": "10.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ed21115d505b4b4f7dc7b5651464e19a2c7f7856" + "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ed21115d505b4b4f7dc7b5651464e19a2c7f7856", - "reference": "ed21115d505b4b4f7dc7b5651464e19a2c7f7856", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6fce887c71076a73f32fd3e0774a6833fc5c7f19", + "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19", "shasum": "" }, "require": { @@ -18955,7 +18921,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.3" }, "funding": [ { @@ -18971,7 +18937,7 @@ "type": "tidelift" } ], - "time": "2023-12-27T15:13:52+00:00" + "time": "2023-12-13T07:25:23+00:00" }, { "name": "pimple/pimple", From e268d4f22699eecd63ad1ad1517c0432a2ec68d4 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 20:19:33 -0500 Subject: [PATCH 32/56] Make null safe Signed-off-by: Kevin Ullyott --- .../src/Filament/Resources/EventResource/Pages/EditEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php index cda81e3d39..11ca44ef15 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php @@ -126,7 +126,7 @@ public function form(Form $form): Form $this->fieldBuilder(), ]) ->hidden(fn (Get $get) => $get('is_wizard')) - ->disabled(fn (?EventRegistrationForm $record) => $record->submissions()->exists()), + ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()), Repeater::make('steps') ->schema([ TextInput::make('label') From dc668f8b145a1dfa7242d3ef20f86cfd9f290f36 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 20:25:48 -0500 Subject: [PATCH 33/56] Fix double hydration issue Signed-off-by: Kevin Ullyott --- .../EventResource/Pages/EditEvent.php | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php index 11ca44ef15..f0c0e8a8f9 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php @@ -69,6 +69,8 @@ class EditEvent extends EditRecord { protected static string $resource = EventResource::class; + protected bool $contentHydrated = false; + public function form(Form $form): Form { /** @var User $user */ @@ -189,7 +191,26 @@ public function fieldBuilder(): TiptapEditor }) ->dehydrated(false) ->columnSpanFull() - ->extraInputAttributes(['style' => 'min-height: 12rem;']); + ->extraInputAttributes(['style' => 'min-height: 12rem;']) + ->afterStateHydrated(function (TiptapEditor $component, string | array | null $state): void { + // TODO: This is a temporary fix until we can figure out whey this gets hydrated twice. + + if (! $state || $this->contentHydrated) { + return; + } + + if (! is_array($state)) { + $state = tiptap_converter()->asJSON($state, decoded: true); + } + + ray('here2'); + + $state = $component->renderBlockPreviews($state, $component); + + $component->state($state); + + $this->contentHydrated = true; + }); } public function saveFieldsFromComponents(EventRegistrationForm $form, array $components, ?EventRegistrationFormStep $eventRegistrationFormStep): array From 6ef9777e700663690c6e10034707f5547ce0a087 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 27 Dec 2023 22:48:40 -0500 Subject: [PATCH 34/56] FIx some bugs with submissions Signed-off-by: Kevin Ullyott --- .../Actions/GenerateSubmissibleEmbedCode.php | 3 +- app-modules/form/src/Models/Submission.php | 2 +- .../render-event-registration-form.blade.php | 2 +- app-modules/meeting-center/routes/api.php | 12 +-- app-modules/meeting-center/routes/web.php | 2 +- .../EventResource/Pages/ViewEvent.php | 6 ++ .../EventRegistrationWidgetController.php | 30 +++++--- ...istrationFormIsEmbeddableAndAuthorized.php | 75 +++++++++++++++++++ .../Livewire/RenderEventRegistrationForm.php | 6 +- .../EventRegistrationFormSubmission.php | 5 ++ ...icateEventRegistrationFormNotification.php | 2 +- app/Http/Middleware/VerifyCsrfToken.php | 1 + 12 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 app-modules/meeting-center/src/Http/Middleware/EnsureEventRegistrationFormIsEmbeddableAndAuthorized.php diff --git a/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php b/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php index ea28b94f01..339d06623d 100644 --- a/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php +++ b/app-modules/form/src/Actions/GenerateSubmissibleEmbedCode.php @@ -77,8 +77,9 @@ public function handle(Submissible $submissible): string EOD; })(), EventRegistrationForm::class => (function () use ($submissible) { + /** @var EventRegistrationForm $submissible */ $scriptUrl = url('js/widgets/events/advising-app-event-registration-form-widget.js?'); - $formDefinitionUrl = URL::signedRoute('event-registration.define', ['form' => $submissible]); + $formDefinitionUrl = URL::signedRoute('event-registration.define', ['event' => $submissible->event]); return << diff --git a/app-modules/form/src/Models/Submission.php b/app-modules/form/src/Models/Submission.php index aa948d8ca1..0816268c2e 100644 --- a/app-modules/form/src/Models/Submission.php +++ b/app-modules/form/src/Models/Submission.php @@ -55,7 +55,7 @@ abstract public function submissible(): BelongsTo; abstract public function fields(): BelongsToMany; - public function author(): MorphTo + public function author(): MorphTo|BelongsTo { return $this ->morphTo('author'); diff --git a/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php b/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php index 26a5435918..e6e327ca9d 100644 --- a/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php +++ b/app-modules/meeting-center/resources/views/livewire/render-event-registration-form.blade.php @@ -37,6 +37,6 @@
- {!! resolve(GenerateSubmissibleEmbedCode::class)->handle($this->eventRegistrationForm) !!} + {!! resolve(GenerateSubmissibleEmbedCode::class)->handle($this->event->eventRegistrationForm) !!}
diff --git a/app-modules/meeting-center/routes/api.php b/app-modules/meeting-center/routes/api.php index 13aa9a6000..1bb564f34d 100644 --- a/app-modules/meeting-center/routes/api.php +++ b/app-modules/meeting-center/routes/api.php @@ -34,28 +34,28 @@ */ -use AdvisingApp\Form\Http\Middleware\EnsureSubmissibleIsEmbeddableAndAuthorized; use AdvisingApp\MeetingCenter\Http\Controllers\EventRegistrationWidgetController; +use AdvisingApp\MeetingCenter\Http\Middleware\EnsureEventRegistrationFormIsEmbeddableAndAuthorized; Route::prefix('api') ->middleware([ 'api', - EnsureSubmissibleIsEmbeddableAndAuthorized::class . ':form', + EnsureEventRegistrationFormIsEmbeddableAndAuthorized::class . ':event', ]) ->group(function () { Route::prefix('event-registration') ->name('event-registration.') ->group(function () { - Route::get('/{form}', [EventRegistrationWidgetController::class, 'view']) + Route::get('/{event}', [EventRegistrationWidgetController::class, 'view']) ->middleware(['signed']) ->name('define'); - Route::post('/{form}/authenticate/request', [EventRegistrationWidgetController::class, 'requestAuthentication']) + Route::post('/{event}/authenticate/request', [EventRegistrationWidgetController::class, 'requestAuthentication']) ->middleware(['signed']) ->name('request-authentication'); - Route::post('/{form}/authenticate/{authentication}', [EventRegistrationWidgetController::class, 'authenticate']) + Route::post('/{event}/authenticate/{authentication}', [EventRegistrationWidgetController::class, 'authenticate']) ->middleware(['signed']) ->name('authenticate'); - Route::post('/{form}/submit', [EventRegistrationWidgetController::class, 'store']) + Route::post('/{event}/submit', [EventRegistrationWidgetController::class, 'store']) ->middleware(['signed']) ->name('submit'); }); diff --git a/app-modules/meeting-center/routes/web.php b/app-modules/meeting-center/routes/web.php index d1b6d06442..b5951e3f04 100644 --- a/app-modules/meeting-center/routes/web.php +++ b/app-modules/meeting-center/routes/web.php @@ -51,6 +51,6 @@ ->prefix('event-registration') ->name('event-registration.') ->group(function () { - Route::get('/{eventRegistrationForm}/respond', RenderEventRegistrationForm::class) + Route::get('/{event}/respond', RenderEventRegistrationForm::class) ->name('show'); }); diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ViewEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ViewEvent.php index 06d58a2b7f..be813c72a9 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ViewEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ViewEvent.php @@ -36,11 +36,13 @@ namespace AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages; +use Filament\Actions\Action; use Filament\Actions\EditAction; use Filament\Infolists\Infolist; use Filament\Actions\DeleteAction; use Filament\Resources\Pages\ViewRecord; use Filament\Infolists\Components\Section; +use AdvisingApp\MeetingCenter\Models\Event; use Filament\Infolists\Components\TextEntry; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; @@ -68,6 +70,10 @@ public function infolist(Infolist $infolist): Infolist protected function getHeaderActions(): array { return [ + Action::make('view') + ->url(fn (Event $event) => route('event-registration.show', ['event' => $event])) + ->icon('heroicon-m-arrow-top-right-on-square') + ->openUrlInNewTab(), EditAction::make(), DeleteAction::make(), ]; diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index 3bd79a987d..d542a26ad2 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -45,30 +45,33 @@ use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; +use AdvisingApp\MeetingCenter\Models\Event; use Illuminate\Support\Facades\Notification; use Symfony\Component\HttpFoundation\Response; use AdvisingApp\Form\Actions\GenerateFormKitSchema; use AdvisingApp\MeetingCenter\Models\EventAttendee; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; use AdvisingApp\Form\Actions\GenerateSubmissibleValidation; -use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; -use AdvisingApp\Form\Actions\ResolveSubmissionAuthorFromEmail; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormSubmission; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; use AdvisingApp\IntegrationGoogleRecaptcha\Settings\GoogleRecaptchaSettings; -use AdvisingApp\Form\Notifications\AuthenticateEventRegistrationFormNotification; +use AdvisingApp\MeetingCenter\Notifications\AuthenticateEventRegistrationFormNotification; class EventRegistrationWidgetController extends Controller { - public function view(GenerateFormKitSchema $generateSchema, EventRegistrationForm $form): JsonResponse + public function view(GenerateFormKitSchema $generateSchema, Event $event): JsonResponse { + $form = $event->eventRegistrationForm; + + ray($event, $form); + return response()->json( [ 'name' => $form->event->title, 'description' => $form->event->description, // TODO: Maybe get rid of this? It would never not be authenticated. 'is_authenticated' => true, - 'authentication_url' => URL::signedRoute('event-registration.request-authentication', ['form' => $form]), + 'authentication_url' => URL::signedRoute('event-registration.request-authentication', ['event' => $event]), 'recaptcha_enabled' => $form->recaptcha_enabled, ...($form->recaptcha_enabled ? [ 'recaptcha_site_key' => app(GoogleRecaptchaSettings::class)->site_key, @@ -80,8 +83,10 @@ public function view(GenerateFormKitSchema $generateSchema, EventRegistrationFor ); } - public function requestAuthentication(Request $request, EventRegistrationForm $form): JsonResponse + public function requestAuthentication(Request $request, Event $event): JsonResponse { + $form = $event->eventRegistrationForm; + $data = $request->validate([ 'email' => ['required', 'email'], ]); @@ -113,13 +118,13 @@ public function requestAuthentication(Request $request, EventRegistrationForm $f return response()->json([ 'message' => "We've sent an authentication code to {$attendee->email}.", 'authentication_url' => URL::signedRoute('event-registration.authenticate', [ - 'form' => $form, + 'event' => $event, 'authentication' => $authentication, ]), ]); } - public function authenticate(Request $request, EventRegistrationForm $form, EventRegistrationFormAuthentication $authentication): JsonResponse + public function authenticate(Request $request, Event $event, EventRegistrationFormAuthentication $authentication): JsonResponse { if ($authentication->isExpired()) { return response()->json([ @@ -140,7 +145,7 @@ public function authenticate(Request $request, EventRegistrationForm $form, Even return response()->json([ 'submission_url' => URL::signedRoute('event-registration.submit', [ 'authentication' => $authentication, - 'form' => $authentication->submissible, + 'event' => $authentication->submissible->event, ]), ]); } @@ -148,9 +153,10 @@ public function authenticate(Request $request, EventRegistrationForm $form, Even public function store( Request $request, GenerateSubmissibleValidation $generateValidation, - ResolveSubmissionAuthorFromEmail $resolveSubmissionAuthorFromEmail, - EventRegistrationForm $form, + Event $event, ): JsonResponse { + $form = $event->eventRegistrationForm; + $authentication = $request->query('authentication'); if (filled($authentication)) { @@ -168,6 +174,8 @@ public function store( $generateValidation($form) ); + ray($validator->errors()); + if ($validator->fails()) { return response()->json( [ diff --git a/app-modules/meeting-center/src/Http/Middleware/EnsureEventRegistrationFormIsEmbeddableAndAuthorized.php b/app-modules/meeting-center/src/Http/Middleware/EnsureEventRegistrationFormIsEmbeddableAndAuthorized.php new file mode 100644 index 0000000000..5d041e18ae --- /dev/null +++ b/app-modules/meeting-center/src/Http/Middleware/EnsureEventRegistrationFormIsEmbeddableAndAuthorized.php @@ -0,0 +1,75 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Http\Middleware; + +use Closure; +use Illuminate\Http\Request; +use AdvisingApp\MeetingCenter\Models\Event; +use Symfony\Component\HttpFoundation\Response; + +class EnsureEventRegistrationFormIsEmbeddableAndAuthorized +{ + public function handle(Request $request, Closure $next, string $binding): Response + { + /** @var Event $event */ + $event = $request->route($binding); + + $submissible = $event->eventRegistrationForm; + + $referer = $request->headers->get('referer'); + + if (! $referer) { + return response()->json(['error' => 'Missing referer header.'], 400); + } + + $referer = parse_url($referer)['host']; + + if ($referer != parse_url(config('app.url'))['host']) { + if (! $submissible->embed_enabled) { + return response()->json(['error' => 'Embedding is not enabled for this form.'], 403); + } + + $allowedDomains = collect($submissible->allowed_domains ?? []); + + if (! $allowedDomains->contains($referer)) { + return response()->json(['error' => 'Referer not allowed. Domain must be added to allowed domains list'], 403); + } + } + + return $next($request); + } +} diff --git a/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php b/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php index 60dc4d9cdf..5a77647953 100644 --- a/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php +++ b/app-modules/meeting-center/src/Livewire/RenderEventRegistrationForm.php @@ -39,8 +39,8 @@ use Livewire\Component; use Illuminate\Contracts\View\View; use Filament\Forms\Contracts\HasForms; +use AdvisingApp\MeetingCenter\Models\Event; use Filament\Forms\Concerns\InteractsWithForms; -use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; class RenderEventRegistrationForm extends Component implements HasForms { @@ -48,13 +48,13 @@ class RenderEventRegistrationForm extends Component implements HasForms public bool $show = true; - public EventRegistrationForm $eventRegistrationForm; + public Event $event; public ?array $data = []; public function render(): View { return view('meeting-center::livewire.render-event-registration-form') - ->title("{$this->eventRegistrationForm->event->title} Registration"); + ->title("{$this->event->title} Registration"); } } diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php index 4a1392f1ae..35fdd58213 100644 --- a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php @@ -85,6 +85,11 @@ public function fields(): BelongsToMany ->withPivot(['id', 'response']); } + public function author(): BelongsTo + { + return $this->belongsTo(EventAttendee::class, 'event_attendee_id'); + } + public function deliverRequest(): void { $this->request_method->deliver($this); diff --git a/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php b/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php index 6719016200..09efa9ae1b 100644 --- a/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php +++ b/app-modules/meeting-center/src/Notifications/AuthenticateEventRegistrationFormNotification.php @@ -34,7 +34,7 @@ */ -namespace AdvisingApp\Form\Notifications; +namespace AdvisingApp\MeetingCenter\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 88dddf1747..660c731b42 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -49,6 +49,7 @@ class VerifyCsrfToken extends Middleware '/api/forms/*', '/api/applications/*', '/api/surveys/*', + '/api/event-registration/*', '/graphql/*', ]; } From 08b83cf4d478993dec70dec94d740dbc3c9ccdaf Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 09:45:12 -0500 Subject: [PATCH 35/56] Fix relationship saving Signed-off-by: Kevin Ullyott --- .../EventResource/Pages/EditEvent.php | 26 ++++++++++++++++--- .../src/Models/EventRegistrationForm.php | 3 +++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php index f0c0e8a8f9..72eda35866 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php @@ -52,6 +52,7 @@ use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\Component; use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\EditRecord; @@ -64,6 +65,7 @@ use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormField; +use Filament\Forms\Components\Contracts\CanEntangleWithSingularRelationships; class EditEvent extends EditRecord { @@ -98,6 +100,24 @@ public function form(Form $form): Form ->required(), Fieldset::make('Registration Form') ->relationship('eventRegistrationForm') + ->saveRelationshipsBeforeChildrenUsing(static function (Component | CanEntangleWithSingularRelationships $component): void { + $component->getCachedExistingRecord()?->delete(); + + $relationship = $component->getRelationship(); + + $data = $component->getChildComponentContainer()->getState(shouldCallHooksBefore: false); + $data = $component->mutateRelationshipDataBeforeCreate($data); + + $relatedModel = $component->getRelatedModel(); + + $record = new $relatedModel(); + $record->fill($data); + + $relationship->save($record); + + $component->cachedExistingRecord($record); + }) + ->saveRelationshipsUsing(null) ->schema([ Grid::make() ->schema([ @@ -203,8 +223,6 @@ public function fieldBuilder(): TiptapEditor $state = tiptap_converter()->asJSON($state, decoded: true); } - ray('here2'); - $state = $component->renderBlockPreviews($state, $component); $component->state($state); @@ -275,14 +293,14 @@ protected function clearFormContentForWizard(): void $form = $event->eventRegistrationForm; - if ($form->is_wizard) { + if ($form?->is_wizard) { $form->content = null; $form->save(); return; } - $form->steps()->delete(); + $form?->steps()->delete(); } protected function getHeaderActions(): array diff --git a/app-modules/meeting-center/src/Models/EventRegistrationForm.php b/app-modules/meeting-center/src/Models/EventRegistrationForm.php index e8ed9f9aa2..66dda93cad 100644 --- a/app-modules/meeting-center/src/Models/EventRegistrationForm.php +++ b/app-modules/meeting-center/src/Models/EventRegistrationForm.php @@ -38,6 +38,7 @@ use AdvisingApp\Form\Enums\Rounding; use AdvisingApp\Form\Models\Submissible; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -46,6 +47,8 @@ */ class EventRegistrationForm extends Submissible { + use SoftDeletes; + protected $fillable = [ 'form_id', 'embed_enabled', From 01fc3389e8352410c77184cbdebda95456a715cd Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 10:58:26 -0500 Subject: [PATCH 36/56] Upgrade filament and remove hydration fix Signed-off-by: Kevin Ullyott --- .../EventResource/Pages/EditEvent.php | 21 +- composer.lock | 237 +++++++++--------- 2 files changed, 119 insertions(+), 139 deletions(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php index 72eda35866..aa11585866 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php @@ -71,8 +71,6 @@ class EditEvent extends EditRecord { protected static string $resource = EventResource::class; - protected bool $contentHydrated = false; - public function form(Form $form): Form { /** @var User $user */ @@ -211,24 +209,7 @@ public function fieldBuilder(): TiptapEditor }) ->dehydrated(false) ->columnSpanFull() - ->extraInputAttributes(['style' => 'min-height: 12rem;']) - ->afterStateHydrated(function (TiptapEditor $component, string | array | null $state): void { - // TODO: This is a temporary fix until we can figure out whey this gets hydrated twice. - - if (! $state || $this->contentHydrated) { - return; - } - - if (! is_array($state)) { - $state = tiptap_converter()->asJSON($state, decoded: true); - } - - $state = $component->renderBlockPreviews($state, $component); - - $component->state($state); - - $this->contentHydrated = true; - }); + ->extraInputAttributes(['style' => 'min-height: 12rem;']); } public function saveFieldsFromComponents(EventRegistrationForm $form, array $components, ?EventRegistrationFormStep $eventRegistrationFormStep): array diff --git a/composer.lock b/composer.lock index 2377067c69..029ba3e12f 100644 --- a/composer.lock +++ b/composer.lock @@ -755,16 +755,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.294.5", + "version": "3.295.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "2e34d45e970c77775e4c298e08732d64b647c41c" + "reference": "7e8f68580954a01cf9c8f2abd4f4db52ebcb7b73" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2e34d45e970c77775e4c298e08732d64b647c41c", - "reference": "2e34d45e970c77775e4c298e08732d64b647c41c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7e8f68580954a01cf9c8f2abd4f4db52ebcb7b73", + "reference": "7e8f68580954a01cf9c8f2abd4f4db52ebcb7b73", "shasum": "" }, "require": { @@ -844,9 +844,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.294.5" + "source": "https://github.com/aws/aws-sdk-php/tree/3.295.2" }, - "time": "2023-12-21T19:10:21+00:00" + "time": "2023-12-27T19:06:10+00:00" }, { "name": "barryvdh/laravel-debugbar", @@ -4071,16 +4071,16 @@ }, { "name": "filament/actions", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", - "reference": "be3a8c110aa69f3f4856816eefd477b600bc06e2" + "reference": "8f2a3df7c607a24c2433a3a71cb27b20a8dea203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/actions/zipball/be3a8c110aa69f3f4856816eefd477b600bc06e2", - "reference": "be3a8c110aa69f3f4856816eefd477b600bc06e2", + "url": "https://api.github.com/repos/filamentphp/actions/zipball/8f2a3df7c607a24c2433a3a71cb27b20a8dea203", + "reference": "8f2a3df7c607a24c2433a3a71cb27b20a8dea203", "shasum": "" }, "require": { @@ -4118,20 +4118,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-21T12:38:03+00:00" + "time": "2023-12-28T15:54:29+00:00" }, { "name": "filament/filament", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "e1aa070483c2eaa5bb92ce8d959779a9558fe022" + "reference": "ae12dc49094560188a4289778a54773045880e44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/e1aa070483c2eaa5bb92ce8d959779a9558fe022", - "reference": "e1aa070483c2eaa5bb92ce8d959779a9558fe022", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/ae12dc49094560188a4289778a54773045880e44", + "reference": "ae12dc49094560188a4289778a54773045880e44", "shasum": "" }, "require": { @@ -4183,20 +4183,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-22T14:36:15+00:00" + "time": "2023-12-28T15:54:35+00:00" }, { "name": "filament/forms", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "673689bd958797b05127fe9956eafeed555b91bd" + "reference": "26e177a4b3a8ef7b8326d992bb5073f02220a506" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/673689bd958797b05127fe9956eafeed555b91bd", - "reference": "673689bd958797b05127fe9956eafeed555b91bd", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/26e177a4b3a8ef7b8326d992bb5073f02220a506", + "reference": "26e177a4b3a8ef7b8326d992bb5073f02220a506", "shasum": "" }, "require": { @@ -4239,20 +4239,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-22T14:36:00+00:00" + "time": "2023-12-28T15:54:30+00:00" }, { "name": "filament/infolists", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", - "reference": "9207c2b83ba9c8dcbcac9a930e93ce87f381d780" + "reference": "66d69c06dbcf74a72dd3a435eda27b1e5e11eaf3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/infolists/zipball/9207c2b83ba9c8dcbcac9a930e93ce87f381d780", - "reference": "9207c2b83ba9c8dcbcac9a930e93ce87f381d780", + "url": "https://api.github.com/repos/filamentphp/infolists/zipball/66d69c06dbcf74a72dd3a435eda27b1e5e11eaf3", + "reference": "66d69c06dbcf74a72dd3a435eda27b1e5e11eaf3", "shasum": "" }, "require": { @@ -4290,20 +4290,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-22T14:36:00+00:00" + "time": "2023-12-26T22:39:20+00:00" }, { "name": "filament/notifications", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", - "reference": "5b9255c0793751534461cace12febdc0d4cc05bb" + "reference": "4f5634f9df312050efa3a035c543add6cec0e3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/notifications/zipball/5b9255c0793751534461cace12febdc0d4cc05bb", - "reference": "5b9255c0793751534461cace12febdc0d4cc05bb", + "url": "https://api.github.com/repos/filamentphp/notifications/zipball/4f5634f9df312050efa3a035c543add6cec0e3a2", + "reference": "4f5634f9df312050efa3a035c543add6cec0e3a2", "shasum": "" }, "require": { @@ -4342,11 +4342,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-17T22:25:42+00:00" + "time": "2023-12-28T15:54:27+00:00" }, { "name": "filament/spatie-laravel-media-library-plugin", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-media-library-plugin.git", @@ -4383,16 +4383,16 @@ }, { "name": "filament/spatie-laravel-settings-plugin", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-settings-plugin.git", - "reference": "7119f3f714dfa0ce098cd90aa2a741147a5508f6" + "reference": "d26f397a845934462d511432ba88363f63a7e203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/spatie-laravel-settings-plugin/zipball/7119f3f714dfa0ce098cd90aa2a741147a5508f6", - "reference": "7119f3f714dfa0ce098cd90aa2a741147a5508f6", + "url": "https://api.github.com/repos/filamentphp/spatie-laravel-settings-plugin/zipball/d26f397a845934462d511432ba88363f63a7e203", + "reference": "d26f397a845934462d511432ba88363f63a7e203", "shasum": "" }, "require": { @@ -4426,20 +4426,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-19T13:24:28+00:00" + "time": "2023-12-26T22:39:37+00:00" }, { "name": "filament/support", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "f00f44dd79e8e1b3f92dea6e2ef6e1ba9e5396dd" + "reference": "97792dad038a87b7a6bfe465c4f1913252c99017" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/f00f44dd79e8e1b3f92dea6e2ef6e1ba9e5396dd", - "reference": "f00f44dd79e8e1b3f92dea6e2ef6e1ba9e5396dd", + "url": "https://api.github.com/repos/filamentphp/support/zipball/97792dad038a87b7a6bfe465c4f1913252c99017", + "reference": "97792dad038a87b7a6bfe465c4f1913252c99017", "shasum": "" }, "require": { @@ -4483,20 +4483,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-22T14:36:21+00:00" + "time": "2023-12-24T21:16:58+00:00" }, { "name": "filament/tables", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "3391bd1015bdde8e454d0a6391952dc131fb8dad" + "reference": "ea8518eeaf15111b4dbd7438a8a00a3c3ab48c67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/3391bd1015bdde8e454d0a6391952dc131fb8dad", - "reference": "3391bd1015bdde8e454d0a6391952dc131fb8dad", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/ea8518eeaf15111b4dbd7438a8a00a3c3ab48c67", + "reference": "ea8518eeaf15111b4dbd7438a8a00a3c3ab48c67", "shasum": "" }, "require": { @@ -4536,20 +4536,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-22T14:36:23+00:00" + "time": "2023-12-28T15:54:29+00:00" }, { "name": "filament/widgets", - "version": "v3.1.27", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", - "reference": "290184b9dfb99436df94a9a0b8511b21811d9e64" + "reference": "7195d2fe7d12a9b9595fa445a4dbedd6d7714836" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/widgets/zipball/290184b9dfb99436df94a9a0b8511b21811d9e64", - "reference": "290184b9dfb99436df94a9a0b8511b21811d9e64", + "url": "https://api.github.com/repos/filamentphp/widgets/zipball/7195d2fe7d12a9b9595fa445a4dbedd6d7714836", + "reference": "7195d2fe7d12a9b9595fa445a4dbedd6d7714836", "shasum": "" }, "require": { @@ -4580,7 +4580,7 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-17T22:26:03+00:00" + "time": "2023-12-24T21:17:06+00:00" }, { "name": "firebase/php-jwt", @@ -5154,16 +5154,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.328.0", + "version": "v0.329.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "211ba786d30a4ab21e012d2b7dbefc49b4fc6a3d" + "reference": "3216fd1b6ba33c5f6658c3581e9723ff21d9acb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/211ba786d30a4ab21e012d2b7dbefc49b4fc6a3d", - "reference": "211ba786d30a4ab21e012d2b7dbefc49b4fc6a3d", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/3216fd1b6ba33c5f6658c3581e9723ff21d9acb7", + "reference": "3216fd1b6ba33c5f6658c3581e9723ff21d9acb7", "shasum": "" }, "require": { @@ -5192,9 +5192,9 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.328.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.329.0" }, - "time": "2023-12-18T01:00:18+00:00" + "time": "2023-12-24T01:02:15+00:00" }, { "name": "google/auth", @@ -6182,16 +6182,16 @@ }, { "name": "laravel/framework", - "version": "v10.38.2", + "version": "v10.39.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "43da808391da3540d44a8dfeb4e46da4ad8f5723" + "reference": "114926b07bfb5fbf2545c03aa2ce5c8c37be650c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/43da808391da3540d44a8dfeb4e46da4ad8f5723", - "reference": "43da808391da3540d44a8dfeb4e46da4ad8f5723", + "url": "https://api.github.com/repos/laravel/framework/zipball/114926b07bfb5fbf2545c03aa2ce5c8c37be650c", + "reference": "114926b07bfb5fbf2545c03aa2ce5c8c37be650c", "shasum": "" }, "require": { @@ -6294,7 +6294,7 @@ "league/flysystem-sftp-v3": "^3.0", "mockery/mockery": "^1.5.1", "nyholm/psr7": "^1.2", - "orchestra/testbench-core": "^8.15.1", + "orchestra/testbench-core": "^8.18", "pda/pheanstalk": "^4.0", "phpstan/phpstan": "^1.4.7", "phpunit/phpunit": "^10.0.7", @@ -6383,20 +6383,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-12-22T14:39:10+00:00" + "time": "2023-12-27T14:26:28+00:00" }, { "name": "laravel/prompts", - "version": "v0.1.13", + "version": "v0.1.14", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "e1379d8ead15edd6cc4369c22274345982edc95a" + "reference": "2219fa9c4b944add1e825c3bdb8ecae8bc503bc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/e1379d8ead15edd6cc4369c22274345982edc95a", - "reference": "e1379d8ead15edd6cc4369c22274345982edc95a", + "url": "https://api.github.com/repos/laravel/prompts/zipball/2219fa9c4b944add1e825c3bdb8ecae8bc503bc6", + "reference": "2219fa9c4b944add1e825c3bdb8ecae8bc503bc6", "shasum": "" }, "require": { @@ -6412,7 +6412,7 @@ "require-dev": { "mockery/mockery": "^1.5", "pestphp/pest": "^2.3", - "phpstan/phpstan": "^1.10", + "phpstan/phpstan": "^1.11", "phpstan/phpstan-mockery": "^1.1" }, "suggest": { @@ -6438,22 +6438,22 @@ ], "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.13" + "source": "https://github.com/laravel/prompts/tree/v0.1.14" }, - "time": "2023-10-27T13:53:59+00:00" + "time": "2023-12-27T04:18:09+00:00" }, { "name": "laravel/sanctum", - "version": "v3.3.2", + "version": "v3.3.3", "source": { "type": "git", "url": "https://github.com/laravel/sanctum.git", - "reference": "e1a272893bec13cf135627f7e156030b3afe1e60" + "reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/e1a272893bec13cf135627f7e156030b3afe1e60", - "reference": "e1a272893bec13cf135627f7e156030b3afe1e60", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/8c104366459739f3ada0e994bcd3e6fd681ce3d5", + "reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5", "shasum": "" }, "require": { @@ -6506,7 +6506,7 @@ "issues": "https://github.com/laravel/sanctum/issues", "source": "https://github.com/laravel/sanctum" }, - "time": "2023-11-03T13:42:14+00:00" + "time": "2023-12-19T18:44:48+00:00" }, { "name": "laravel/scout", @@ -12914,16 +12914,16 @@ }, { "name": "spatie/temporary-directory", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/spatie/temporary-directory.git", - "reference": "efc258c9f4da28f0c7661765b8393e4ccee3d19c" + "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/efc258c9f4da28f0c7661765b8393e4ccee3d19c", - "reference": "efc258c9f4da28f0c7661765b8393e4ccee3d19c", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a", + "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a", "shasum": "" }, "require": { @@ -12959,7 +12959,7 @@ ], "support": { "issues": "https://github.com/spatie/temporary-directory/issues", - "source": "https://github.com/spatie/temporary-directory/tree/2.2.0" + "source": "https://github.com/spatie/temporary-directory/tree/2.2.1" }, "funding": [ { @@ -12971,7 +12971,7 @@ "type": "github" } ], - "time": "2023-09-25T07:13:36+00:00" + "time": "2023-12-25T11:46:58+00:00" }, { "name": "sqids/sqids", @@ -15486,21 +15486,21 @@ }, { "name": "symfony/service-contracts", - "version": "v3.4.0", + "version": "v3.4.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838" + "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838", - "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", + "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -15548,7 +15548,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" }, "funding": [ { @@ -15564,7 +15564,7 @@ "type": "tidelift" } ], - "time": "2023-07-30T20:28:31+00:00" + "time": "2023-12-26T14:02:43+00:00" }, { "name": "symfony/string", @@ -15749,16 +15749,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.4.0", + "version": "v3.4.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "dee0c6e5b4c07ce851b462530088e64b255ac9c5" + "reference": "06450585bf65e978026bda220cdebca3f867fde7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/dee0c6e5b4c07ce851b462530088e64b255ac9c5", - "reference": "dee0c6e5b4c07ce851b462530088e64b255ac9c5", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7", + "reference": "06450585bf65e978026bda220cdebca3f867fde7", "shasum": "" }, "require": { @@ -15807,7 +15807,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1" }, "funding": [ { @@ -15823,7 +15823,7 @@ "type": "tidelift" } ], - "time": "2023-07-25T15:08:44+00:00" + "time": "2023-12-26T14:02:43+00:00" }, { "name": "symfony/uid", @@ -17148,16 +17148,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.41.1", + "version": "v3.42.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6" + "reference": "632ef1be3447a9b890bef06147475facee535d0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8b6ae8dcbaf23f09680643ab832a4a3a260265f6", - "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/632ef1be3447a9b890bef06147475facee535d0f", + "reference": "632ef1be3447a9b890bef06147475facee535d0f", "shasum": "" }, "require": { @@ -17188,7 +17188,6 @@ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", "phpunit/phpunit": "^9.6", - "symfony/phpunit-bridge": "^6.3.8 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { @@ -17227,7 +17226,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.41.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.42.0" }, "funding": [ { @@ -17235,7 +17234,7 @@ "type": "github" } ], - "time": "2023-12-10T19:59:27+00:00" + "time": "2023-12-24T14:38:51+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -17753,36 +17752,36 @@ }, { "name": "pestphp/pest", - "version": "v2.28.1", + "version": "v2.30.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "9ee41910201ef8fc5f5b6d1390e5ec4558222927" + "reference": "97dc32f9d24b84dd071d9e89438a19e43c833f6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/9ee41910201ef8fc5f5b6d1390e5ec4558222927", - "reference": "9ee41910201ef8fc5f5b6d1390e5ec4558222927", + "url": "https://api.github.com/repos/pestphp/pest/zipball/97dc32f9d24b84dd071d9e89438a19e43c833f6f", + "reference": "97dc32f9d24b84dd071d9e89438a19e43c833f6f", "shasum": "" }, "require": { "brianium/paratest": "^7.3.1", - "nunomaduro/collision": "^7.10.0|^8.0.0", + "nunomaduro/collision": "^7.10.0|^8.0.1", "nunomaduro/termwind": "^1.15.1|^2.0.0", "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.5.0", "php": "^8.1.0", - "phpunit/phpunit": "^10.5.3" + "phpunit/phpunit": "^10.5.5" }, "conflict": { - "phpunit/phpunit": ">10.5.3", + "phpunit/phpunit": ">10.5.5", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, "require-dev": { "pestphp/pest-dev-tools": "^2.16.0", - "pestphp/pest-plugin-type-coverage": "^2.5.0", - "symfony/process": "^6.4.0|^7.0.1" + "pestphp/pest-plugin-type-coverage": "^2.6.0", + "symfony/process": "^6.4.0|^7.0.0" }, "bin": [ "bin/pest" @@ -17845,7 +17844,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.28.1" + "source": "https://github.com/pestphp/pest/tree/v2.30.0" }, "funding": [ { @@ -17857,7 +17856,7 @@ "type": "github" } ], - "time": "2023-12-15T11:42:34+00:00" + "time": "2023-12-28T10:36:40+00:00" }, { "name": "pestphp/pest-plugin", @@ -18840,16 +18839,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.3", + "version": "10.5.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19" + "reference": "ed21115d505b4b4f7dc7b5651464e19a2c7f7856" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6fce887c71076a73f32fd3e0774a6833fc5c7f19", - "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ed21115d505b4b4f7dc7b5651464e19a2c7f7856", + "reference": "ed21115d505b4b4f7dc7b5651464e19a2c7f7856", "shasum": "" }, "require": { @@ -18921,7 +18920,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.5" }, "funding": [ { @@ -18937,7 +18936,7 @@ "type": "tidelift" } ], - "time": "2023-12-13T07:25:23+00:00" + "time": "2023-12-27T15:13:52+00:00" }, { "name": "pimple/pimple", From 98f8b4fa69c33468216f2fd05ae12bc36f471077 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 12:15:40 -0500 Subject: [PATCH 37/56] Fix issue with signed urls Signed-off-by: Kevin Ullyott --- .../src/Http/Controllers/EventRegistrationWidgetController.php | 2 -- app/Providers/AppServiceProvider.php | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index d542a26ad2..eee1f4c4a1 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -63,8 +63,6 @@ public function view(GenerateFormKitSchema $generateSchema, Event $event): JsonR { $form = $event->eventRegistrationForm; - ray($event, $form); - return response()->json( [ 'name' => $form->event->title, diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index f54cc6fd41..4483cd73a2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -64,6 +64,7 @@ public function boot(): void if (config('app.force_https')) { URL::forceScheme('https'); + $this->app['request']->server->set('HTTPS', true); } } } From c22597505c509953ee42e86800095b7eecc0b763 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 12:29:06 -0500 Subject: [PATCH 38/56] Share event configuration between create and edit Signed-off-by: Kevin Ullyott --- .../HasSharedEventFormConfiguration.php | 245 ++++++++++++++++++ .../EventResource/Pages/CreateEvent.php | 32 +-- .../EventResource/Pages/EditEvent.php | 238 +---------------- 3 files changed, 253 insertions(+), 262 deletions(-) create mode 100644 app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php new file mode 100644 index 0000000000..f3de80786e --- /dev/null +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php @@ -0,0 +1,245 @@ +user(); + + return [ + TextInput::make('title') + ->string() + ->required(), + Textarea::make('description') + ->string() + ->nullable(), + TextInput::make('location') + ->string() + ->nullable(), + TextInput::make('capacity') + ->integer() + ->minValue(1) + ->nullable(), + DateTimePicker::make('starts_at') + ->timezone($user->timezone) + ->required(), + DateTimePicker::make('ends_at') + ->timezone($user->timezone) + ->required(), + Fieldset::make('Registration Form') + ->relationship('eventRegistrationForm') + ->saveRelationshipsBeforeChildrenUsing(static function (Component | CanEntangleWithSingularRelationships $component): void { + $component->getCachedExistingRecord()?->delete(); + + $relationship = $component->getRelationship(); + + $data = $component->getChildComponentContainer()->getState(shouldCallHooksBefore: false); + $data = $component->mutateRelationshipDataBeforeCreate($data); + + $relatedModel = $component->getRelatedModel(); + + $record = new $relatedModel(); + $record->fill($data); + + $relationship->save($record); + + $component->cachedExistingRecord($record); + }) + ->saveRelationshipsUsing(null) + ->schema([ + Grid::make() + ->schema([ + Toggle::make('embed_enabled') + ->label('Embed Enabled') + ->live() + ->helperText('If enabled, this form can be embedded on other websites.'), + TagsInput::make('allowed_domains') + ->label('Allowed Domains') + ->helperText('Only these domains will be allowed to embed this form.') + ->placeholder('example.com') + ->hidden(fn (Get $get) => ! $get('embed_enabled')) + ->disabled(fn (Get $get) => ! $get('embed_enabled')) + ->nestedRecursiveRules( + [ + 'string', + new IsDomain(), + ] + ), + ]) + ->columnSpanFull(), + Toggle::make('is_wizard') + ->label('Multi-step form') + ->live() + ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()), + Section::make('Fields') + ->schema([ + $this->fieldBuilder(), + ]) + ->hidden(fn (Get $get) => $get('is_wizard')) + ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()), + Repeater::make('steps') + ->schema([ + TextInput::make('label') + ->required() + ->string() + ->maxLength(255) + ->autocomplete(false) + ->columnSpanFull() + ->lazy(), + $this->fieldBuilder(), + ]) + ->addActionLabel('New step') + ->itemLabel(fn (array $state): ?string => $state['label'] ?? null) + ->visible(fn (Get $get) => $get('is_wizard')) + ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()) + ->relationship() + ->reorderable() + ->columnSpanFull(), + Section::make('Appearance') + ->schema([ + ColorSelect::make('primary_color'), + Select::make('rounding') + ->options(Rounding::class), + ]) + ->columns(), + ]), + ]; + } + + public function fieldBuilder(): TiptapEditor + { + return TiptapEditor::make('content') + ->output(TiptapOutput::Json) + ->blocks(FormFieldBlockRegistry::get()) + ->tools(['bold', 'italic', 'small', '|', 'heading', 'bullet-list', 'ordered-list', 'hr', '|', 'link', 'grid', 'blocks']) + ->placeholder('Drag blocks here to build your form') + ->hiddenLabel() + ->saveRelationshipsUsing(function (TiptapEditor $component, EventRegistrationForm | EventRegistrationFormStep $record) { + if ($component->isDisabled()) { + return; + } + + $form = $record instanceof EventRegistrationForm ? $record : $record->submissible; + $formStep = $record instanceof EventRegistrationFormStep ? $record : null; + + EventRegistrationFormStep::query() + ->whereBelongsTo($form, 'submissible') + ->when($formStep, fn (EloquentBuilder $query) => $query->whereBelongsTo($formStep, 'step')) + ->delete(); + + $content = $component->decodeBlocksBeforeSave($component->getJSON(decoded: true)); + $content['content'] = $this->saveFieldsFromComponents( + $form, + $content['content'] ?? [], + $formStep, + ); + + $record->content = $content; + $record->save(); + }) + ->dehydrated(false) + ->columnSpanFull() + ->extraInputAttributes(['style' => 'min-height: 12rem;']); + } + + public function saveFieldsFromComponents(EventRegistrationForm $form, array $components, ?EventRegistrationFormStep $eventRegistrationFormStep): array + { + foreach ($components as $componentKey => $component) { + if (array_key_exists('content', $component)) { + $components[$componentKey]['content'] = $this->saveFieldsFromComponents($form, $component['content'], $eventRegistrationFormStep); + + continue; + } + + if ($component['type'] !== 'tiptapBlock') { + continue; + } + + $componentAttributes = $component['attrs'] ?? []; + + if (array_key_exists('id', $componentAttributes)) { + $id = $componentAttributes['id'] ?? null; + unset($componentAttributes['id']); + } + + if (array_key_exists('label', $componentAttributes['data'])) { + $label = $componentAttributes['data']['label'] ?? null; + unset($componentAttributes['data']['label']); + } + + if (array_key_exists('isRequired', $componentAttributes['data'])) { + $isRequired = $componentAttributes['data']['isRequired'] ?? null; + unset($componentAttributes['data']['isRequired']); + } + + /** @var EventRegistrationFormField $field */ + $field = $form->fields()->findOrNew($id ?? null); + $field->step()->associate($eventRegistrationFormStep); + $field->label = $label ?? $componentAttributes['type']; + $field->is_required = $isRequired ?? false; + $field->type = $componentAttributes['type']; + $field->config = $componentAttributes['data']; + $field->save(); + + $components[$componentKey]['attrs']['id'] = $field->id; + } + + return $components; + } + + protected function afterCreate(): void + { + $this->clearFormContentForWizard(); + } + + protected function afterSave(): void + { + $this->clearFormContentForWizard(); + } + + protected function clearFormContentForWizard(): void + { + /** @var Event $event */ + $event = $this->record; + + $form = $event->eventRegistrationForm; + + if ($form?->is_wizard) { + $form->content = null; + $form->save(); + + return; + } + + $form?->steps()->delete(); + } +} diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/CreateEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/CreateEvent.php index 5fb7b12ea2..28a87776c3 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/CreateEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/CreateEvent.php @@ -36,43 +36,19 @@ namespace AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages; -use App\Models\User; use Filament\Forms\Form; -use Filament\Forms\Components\Textarea; -use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\CreateRecord; -use Filament\Forms\Components\DateTimePicker; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; +use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\Concerns\HasSharedEventFormConfiguration; class CreateEvent extends CreateRecord { + use HasSharedEventFormConfiguration; + protected static string $resource = EventResource::class; public function form(Form $form): Form { - /** @var User $user */ - $user = auth()->user(); - - return $form->schema([ - TextInput::make('title') - ->string() - ->required(), - Textarea::make('description') - ->string() - ->nullable(), - TextInput::make('location') - ->string() - ->nullable(), - TextInput::make('capacity') - ->integer() - ->minValue(1) - ->nullable(), - DateTimePicker::make('starts_at') - ->timezone($user->timezone) - ->required(), - DateTimePicker::make('ends_at') - ->timezone($user->timezone) - ->required(), - ]); + return $form->schema($this->fields()); } } diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php index aa11585866..7e8a652fdf 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/EditEvent.php @@ -36,252 +36,22 @@ namespace AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages; -use App\Models\User; -use Filament\Forms\Get; use Filament\Forms\Form; use Filament\Actions\ViewAction; use Filament\Actions\DeleteAction; -use Filament\Forms\Components\Grid; -use AdvisingApp\Form\Enums\Rounding; -use AdvisingApp\Form\Rules\IsDomain; -use App\Forms\Components\ColorSelect; -use Filament\Forms\Components\Select; -use Filament\Forms\Components\Toggle; -use Filament\Forms\Components\Section; -use FilamentTiptapEditor\TiptapEditor; -use Filament\Forms\Components\Fieldset; -use Filament\Forms\Components\Repeater; -use Filament\Forms\Components\Textarea; -use Filament\Forms\Components\Component; -use Filament\Forms\Components\TagsInput; -use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\EditRecord; -use AdvisingApp\MeetingCenter\Models\Event; -use FilamentTiptapEditor\Enums\TiptapOutput; -use Filament\Forms\Components\DateTimePicker; -use AdvisingApp\MeetingCenter\Models\EventRegistrationForm; -use AdvisingApp\Form\Filament\Blocks\FormFieldBlockRegistry; -use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; -use AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep; -use AdvisingApp\MeetingCenter\Models\EventRegistrationFormField; -use Filament\Forms\Components\Contracts\CanEntangleWithSingularRelationships; +use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\Concerns\HasSharedEventFormConfiguration; class EditEvent extends EditRecord { + use HasSharedEventFormConfiguration; + protected static string $resource = EventResource::class; public function form(Form $form): Form { - /** @var User $user */ - $user = auth()->user(); - - return $form->schema([ - TextInput::make('title') - ->string() - ->required(), - Textarea::make('description') - ->string() - ->nullable(), - TextInput::make('location') - ->string() - ->nullable(), - TextInput::make('capacity') - ->integer() - ->minValue(1) - ->nullable(), - DateTimePicker::make('starts_at') - ->timezone($user->timezone) - ->required(), - DateTimePicker::make('ends_at') - ->timezone($user->timezone) - ->required(), - Fieldset::make('Registration Form') - ->relationship('eventRegistrationForm') - ->saveRelationshipsBeforeChildrenUsing(static function (Component | CanEntangleWithSingularRelationships $component): void { - $component->getCachedExistingRecord()?->delete(); - - $relationship = $component->getRelationship(); - - $data = $component->getChildComponentContainer()->getState(shouldCallHooksBefore: false); - $data = $component->mutateRelationshipDataBeforeCreate($data); - - $relatedModel = $component->getRelatedModel(); - - $record = new $relatedModel(); - $record->fill($data); - - $relationship->save($record); - - $component->cachedExistingRecord($record); - }) - ->saveRelationshipsUsing(null) - ->schema([ - Grid::make() - ->schema([ - Toggle::make('embed_enabled') - ->label('Embed Enabled') - ->live() - ->helperText('If enabled, this form can be embedded on other websites.'), - TagsInput::make('allowed_domains') - ->label('Allowed Domains') - ->helperText('Only these domains will be allowed to embed this form.') - ->placeholder('example.com') - ->hidden(fn (Get $get) => ! $get('embed_enabled')) - ->disabled(fn (Get $get) => ! $get('embed_enabled')) - ->nestedRecursiveRules( - [ - 'string', - new IsDomain(), - ] - ), - ]) - ->columnSpanFull(), - Toggle::make('is_wizard') - ->label('Multi-step form') - ->live() - ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()), - Section::make('Fields') - ->schema([ - $this->fieldBuilder(), - ]) - ->hidden(fn (Get $get) => $get('is_wizard')) - ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()), - Repeater::make('steps') - ->schema([ - TextInput::make('label') - ->required() - ->string() - ->maxLength(255) - ->autocomplete(false) - ->columnSpanFull() - ->lazy(), - $this->fieldBuilder(), - ]) - ->addActionLabel('New step') - ->itemLabel(fn (array $state): ?string => $state['label'] ?? null) - ->visible(fn (Get $get) => $get('is_wizard')) - ->disabled(fn (?EventRegistrationForm $record) => $record?->submissions()->exists()) - ->relationship() - ->reorderable() - ->columnSpanFull(), - Section::make('Appearance') - ->schema([ - ColorSelect::make('primary_color'), - Select::make('rounding') - ->options(Rounding::class), - ]) - ->columns(), - ]), - ]); - } - - public function fieldBuilder(): TiptapEditor - { - return TiptapEditor::make('content') - ->output(TiptapOutput::Json) - ->blocks(FormFieldBlockRegistry::get()) - ->tools(['bold', 'italic', 'small', '|', 'heading', 'bullet-list', 'ordered-list', 'hr', '|', 'link', 'grid', 'blocks']) - ->placeholder('Drag blocks here to build your form') - ->hiddenLabel() - ->saveRelationshipsUsing(function (TiptapEditor $component, EventRegistrationForm | EventRegistrationFormStep $record) { - if ($component->isDisabled()) { - return; - } - - $form = $record instanceof EventRegistrationForm ? $record : $record->submissible; - $formStep = $record instanceof EventRegistrationFormStep ? $record : null; - - EventRegistrationFormStep::query() - ->whereBelongsTo($form, 'submissible') - ->when($formStep, fn (EloquentBuilder $query) => $query->whereBelongsTo($formStep, 'step')) - ->delete(); - - $content = $component->decodeBlocksBeforeSave($component->getJSON(decoded: true)); - $content['content'] = $this->saveFieldsFromComponents( - $form, - $content['content'] ?? [], - $formStep, - ); - - $record->content = $content; - $record->save(); - }) - ->dehydrated(false) - ->columnSpanFull() - ->extraInputAttributes(['style' => 'min-height: 12rem;']); - } - - public function saveFieldsFromComponents(EventRegistrationForm $form, array $components, ?EventRegistrationFormStep $eventRegistrationFormStep): array - { - foreach ($components as $componentKey => $component) { - if (array_key_exists('content', $component)) { - $components[$componentKey]['content'] = $this->saveFieldsFromComponents($form, $component['content'], $eventRegistrationFormStep); - - continue; - } - - if ($component['type'] !== 'tiptapBlock') { - continue; - } - - $componentAttributes = $component['attrs'] ?? []; - - if (array_key_exists('id', $componentAttributes)) { - $id = $componentAttributes['id'] ?? null; - unset($componentAttributes['id']); - } - - if (array_key_exists('label', $componentAttributes['data'])) { - $label = $componentAttributes['data']['label'] ?? null; - unset($componentAttributes['data']['label']); - } - - if (array_key_exists('isRequired', $componentAttributes['data'])) { - $isRequired = $componentAttributes['data']['isRequired'] ?? null; - unset($componentAttributes['data']['isRequired']); - } - - /** @var EventRegistrationFormField $field */ - $field = $form->fields()->findOrNew($id ?? null); - $field->step()->associate($eventRegistrationFormStep); - $field->label = $label ?? $componentAttributes['type']; - $field->is_required = $isRequired ?? false; - $field->type = $componentAttributes['type']; - $field->config = $componentAttributes['data']; - $field->save(); - - $components[$componentKey]['attrs']['id'] = $field->id; - } - - return $components; - } - - protected function afterCreate(): void - { - $this->clearFormContentForWizard(); - } - - protected function afterSave(): void - { - $this->clearFormContentForWizard(); - } - - protected function clearFormContentForWizard(): void - { - /** @var Event $event */ - $event = $this->record; - - $form = $event->eventRegistrationForm; - - if ($form?->is_wizard) { - $form->content = null; - $form->save(); - - return; - } - - $form?->steps()->delete(); + return $form->schema($this->fields()); } protected function getHeaderActions(): array From 265ed0c8b32eb15ac91dd7452402134ef15949fb Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 13:03:40 -0500 Subject: [PATCH 39/56] Start working on adding the content Signed-off-by: Kevin Ullyott --- .../src/Actions/GenerateFormKitSchema.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app-modules/form/src/Actions/GenerateFormKitSchema.php b/app-modules/form/src/Actions/GenerateFormKitSchema.php index 1ce5fa3530..21b693588d 100644 --- a/app-modules/form/src/Actions/GenerateFormKitSchema.php +++ b/app-modules/form/src/Actions/GenerateFormKitSchema.php @@ -68,6 +68,32 @@ public function __invoke(Submissible $submissible): array ]; } + $content = [ + [ + '$formkit' => 'radio', + 'label' => 'Will you be attending?', + 'name' => 'attending', + 'options' => [ + [ + 'label' => 'Yes', + 'value' => 'yes', + ], + [ + 'label' => 'No', + 'value' => 'no', + ], + ], + 'validation' => 'required', + ], + [ + '$el' => 'div', + 'attrs' => [ + 'if' => '$get(form).values.attending === "yes"', + ], + 'children' => $content, + ], + ]; + return [ '$cmp' => 'FormKit', 'props' => [ From d140a07e5c5467a5b031f5f6bf1e113a41d073d4 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 14:17:45 -0500 Subject: [PATCH 40/56] Fix data saving issues Signed-off-by: Kevin Ullyott --- .../src/Actions/GenerateFormKitSchema.php | 11 +++-- .../EventRegistrationWidgetController.php | 43 +++++++++++-------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/app-modules/form/src/Actions/GenerateFormKitSchema.php b/app-modules/form/src/Actions/GenerateFormKitSchema.php index 21b693588d..f9f19e2ede 100644 --- a/app-modules/form/src/Actions/GenerateFormKitSchema.php +++ b/app-modules/form/src/Actions/GenerateFormKitSchema.php @@ -72,6 +72,7 @@ public function __invoke(Submissible $submissible): array [ '$formkit' => 'radio', 'label' => 'Will you be attending?', + 'id' => 'attending', 'name' => 'attending', 'options' => [ [ @@ -87,11 +88,15 @@ public function __invoke(Submissible $submissible): array ], [ '$el' => 'div', - 'attrs' => [ - 'if' => '$get(form).values.attending === "yes"', - ], + 'if' => '$get(attending).value === "yes"', 'children' => $content, ], + [ + '$formkit' => 'submit', + 'if' => '$get(attending).value === "no"', + 'label' => 'Submit', + 'disabled' => '$get(form).state.valid !== true', + ], ]; return [ diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index eee1f4c4a1..19672440e5 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -167,12 +167,17 @@ public function store( abort(Response::HTTP_UNAUTHORIZED); } + // TODO See if we can make attending a bool + $validator = Validator::make( $request->all(), - $generateValidation($form) + [ + 'attending' => ['required', 'in:yes,no'], + ...$request->get('attending') === 'yes' ? $generateValidation($form) : [], + ] ); - ray($validator->errors()); + //ray($validator->errors()); if ($validator->fails()) { return response()->json( @@ -192,33 +197,37 @@ public function store( $submission->submitted_at = now(); - // TODO: Adjust the status of the EventAttendee to Attending or Not Attending based on the form submission. - $submission->save(); + $authentication->author->update(['status' => $request->get('attending') === 'yes' ? EventAttendeeStatus::Attending : EventAttendeeStatus::NotAttending]); + $data = $validator->validated(); - unset($data['recaptcha-token']); + // TODO: change the EventFormSubmission to have a column to store the attending data item + + if ($data['attending'] === 'yes') { + unset($data['recaptcha-token'], $data['attending']); - if ($form->is_wizard) { - foreach ($form->steps as $step) { - foreach ($data[$step->label] as $fieldId => $response) { + if ($form->is_wizard) { + foreach ($form->steps as $step) { + foreach ($data[$step->label] as $fieldId => $response) { + $submission->fields()->attach( + $fieldId, + ['id' => Str::orderedUuid(), 'response' => $response], + ); + } + } + } else { + foreach ($data as $fieldId => $response) { $submission->fields()->attach( $fieldId, ['id' => Str::orderedUuid(), 'response' => $response], ); } } - } else { - foreach ($data as $fieldId => $response) { - $submission->fields()->attach( - $fieldId, - ['id' => Str::orderedUuid(), 'response' => $response], - ); - } - } - $submission->save(); + $submission->save(); + } return response()->json( [ From b4d7b4c40b9a574d66c82fdf1a925a8829d504f3 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 14:39:38 -0500 Subject: [PATCH 41/56] Fix more issues Signed-off-by: Kevin Ullyott --- ...nt_registration_form_submissions_table.php | 1 + .../EventRegistrationWidgetController.php | 108 ++++++++++-------- .../EventRegistrationFormSubmission.php | 3 + widgets/event-registration/src/App.vue | 13 ++- 4 files changed, 72 insertions(+), 53 deletions(-) diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php index 0165143dbd..2b362933c9 100644 --- a/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php @@ -46,6 +46,7 @@ public function up(): void $table->foreignUuid('form_id')->constrained('event_registration_forms')->cascadeOnDelete(); $table->foreignUuid('event_attendee_id')->constrained('event_attendees')->cascadeOnDelete(); + $table->string('attendee_status'); $table->timestamp('submitted_at')->nullable(); $table->timestamp('canceled_at')->nullable(); $table->string('request_method')->nullable(); diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index 19672440e5..bae23c1cbd 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -37,10 +37,12 @@ namespace AdvisingApp\MeetingCenter\Http\Controllers; use Closure; +use Exception; use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Http\JsonResponse; use Filament\Support\Colors\Color; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\URL; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Hash; @@ -153,80 +155,88 @@ public function store( GenerateSubmissibleValidation $generateValidation, Event $event, ): JsonResponse { - $form = $event->eventRegistrationForm; - - $authentication = $request->query('authentication'); + try { + DB::beginTransaction(); - if (filled($authentication)) { - $authentication = EventRegistrationFormAuthentication::findOrFail($authentication); - } - - if ( - ($authentication?->isExpired() ?? true) - ) { - abort(Response::HTTP_UNAUTHORIZED); - } + $form = $event->eventRegistrationForm; - // TODO See if we can make attending a bool + $authentication = $request->query('authentication'); - $validator = Validator::make( - $request->all(), - [ - 'attending' => ['required', 'in:yes,no'], - ...$request->get('attending') === 'yes' ? $generateValidation($form) : [], - ] - ); + if (filled($authentication)) { + $authentication = EventRegistrationFormAuthentication::findOrFail($authentication); + } - //ray($validator->errors()); + if ( + ($authentication?->isExpired() ?? true) + ) { + abort(Response::HTTP_UNAUTHORIZED); + } - if ($validator->fails()) { - return response()->json( + $validator = Validator::make( + $request->all(), [ - 'errors' => (object) $validator->errors(), - ], - Response::HTTP_UNPROCESSABLE_ENTITY + 'attending' => ['required', 'in:yes,no'], + ...$request->get('attending') === 'yes' ? $generateValidation($form) : [], + ] ); - } - /** @var EventRegistrationFormSubmission $submission */ - $submission = $form->submissions()->make(); + if ($validator->fails()) { + return response()->json( + [ + 'errors' => (object) $validator->errors(), + ], + Response::HTTP_UNPROCESSABLE_ENTITY + ); + } - $submission->author()->associate($authentication->author); + /** @var EventRegistrationFormSubmission $submission */ + $submission = $form->submissions()->make(); - $authentication->delete(); + $submission->author()->associate($authentication->author); - $submission->submitted_at = now(); + $authentication->delete(); - $submission->save(); + $submission->submitted_at = now(); - $authentication->author->update(['status' => $request->get('attending') === 'yes' ? EventAttendeeStatus::Attending : EventAttendeeStatus::NotAttending]); + $submission->attendee_status = $request->get('attending') === 'yes' ? EventAttendeeStatus::Attending : EventAttendeeStatus::NotAttending; - $data = $validator->validated(); + $submission->save(); - // TODO: change the EventFormSubmission to have a column to store the attending data item + $authentication->author->update(['status' => $request->get('attending') === 'yes' ? EventAttendeeStatus::Attending : EventAttendeeStatus::NotAttending]); - if ($data['attending'] === 'yes') { - unset($data['recaptcha-token'], $data['attending']); + $data = $validator->validated(); - if ($form->is_wizard) { - foreach ($form->steps as $step) { - foreach ($data[$step->label] as $fieldId => $response) { + if ($data['attending'] === 'yes') { + unset($data['recaptcha-token']); + + if ($form->is_wizard) { + foreach ($form->steps as $step) { + foreach ($data[$step->label] as $fieldId => $response) { + $submission->fields()->attach( + $fieldId, + ['id' => Str::orderedUuid(), 'response' => $response], + ); + } + } + } else { + foreach ($data as $fieldId => $response) { $submission->fields()->attach( $fieldId, ['id' => Str::orderedUuid(), 'response' => $response], ); } } - } else { - foreach ($data as $fieldId => $response) { - $submission->fields()->attach( - $fieldId, - ['id' => Str::orderedUuid(), 'response' => $response], - ); - } + + $submission->save(); } - $submission->save(); + DB::commit(); + } catch (Exception $e) { + // TODO: Tag and report this exception. Send the tag to the frontend as a reference. + + DB::rollBack(); + + throw $e; } return response()->json( diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php index 35fdd58213..2c6aba5124 100644 --- a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php @@ -41,6 +41,7 @@ use Illuminate\Database\Eloquent\Builder; use AdvisingApp\Form\Enums\FormSubmissionStatus; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use AdvisingApp\Form\Enums\FormSubmissionRequestDeliveryMethod; @@ -52,6 +53,7 @@ class EventRegistrationFormSubmission extends Submission protected $fillable = [ 'canceled_at', 'form_id', + 'attendee_status', 'request_method', 'request_note', 'submitted_at', @@ -61,6 +63,7 @@ class EventRegistrationFormSubmission extends Submission 'submitted_at' => 'immutable_datetime', 'canceled_at' => 'immutable_datetime', 'request_method' => FormSubmissionRequestDeliveryMethod::class, + 'attendee_status' => EventAttendeeStatus::class, ]; public function submissible(): BelongsTo diff --git a/widgets/event-registration/src/App.vue b/widgets/event-registration/src/App.vue index 78579b05e8..da5a68bd65 100644 --- a/widgets/event-registration/src/App.vue +++ b/widgets/event-registration/src/App.vue @@ -93,10 +93,15 @@ const data = reactive({ }, body: JSON.stringify(data), }) - .then((response) => response.json()) - .then((json) => { - if (json.errors) { - node.setErrors([], json.errors); + .then((response) => { + if (response.status === 500) { + node.setErrors(['An error occurred while submitting the form. Please try again later.']); + + return; + } + + if (response.json().errors) { + node.setErrors([], response.json().errors); return; } From 0cc9f6656d3193650b9b0110de392ae01cbbb51b Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 15:56:26 -0500 Subject: [PATCH 42/56] Remove todo Signed-off-by: Kevin Ullyott --- .../src/Http/Controllers/EventRegistrationWidgetController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index bae23c1cbd..bc9d4fe1d2 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -69,7 +69,6 @@ public function view(GenerateFormKitSchema $generateSchema, Event $event): JsonR [ 'name' => $form->event->title, 'description' => $form->event->description, - // TODO: Maybe get rid of this? It would never not be authenticated. 'is_authenticated' => true, 'authentication_url' => URL::signedRoute('event-registration.request-authentication', ['event' => $event]), 'recaptcha_enabled' => $form->recaptcha_enabled, From 38fb9d03ff242c1efe29daf25f844bcae1af481c Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 16:00:34 -0500 Subject: [PATCH 43/56] Split the generation logic Signed-off-by: Kevin Ullyott --- .../src/Actions/GenerateFormKitSchema.php | 60 ++++++------------- ...GenerateEventRegistrationFormKitSchema.php | 57 ++++++++++++++++++ .../EventRegistrationWidgetController.php | 4 +- 3 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php diff --git a/app-modules/form/src/Actions/GenerateFormKitSchema.php b/app-modules/form/src/Actions/GenerateFormKitSchema.php index f9f19e2ede..42168bffb5 100644 --- a/app-modules/form/src/Actions/GenerateFormKitSchema.php +++ b/app-modules/form/src/Actions/GenerateFormKitSchema.php @@ -44,6 +44,23 @@ class GenerateFormKitSchema { public function __invoke(Submissible $submissible): array + { + $content = $this->generateContent($submissible); + + return [ + '$cmp' => 'FormKit', + 'props' => [ + 'type' => 'form', + 'id' => 'form', + 'onSubmit' => '$submitForm', + 'plugins' => '$plugins', + 'actions' => false, + ], + 'children' => $content, + ]; + } + + public function generateContent(Submissible $submissible): array { if ($submissible->is_wizard) { $submissible->loadMissing([ @@ -68,48 +85,7 @@ public function __invoke(Submissible $submissible): array ]; } - $content = [ - [ - '$formkit' => 'radio', - 'label' => 'Will you be attending?', - 'id' => 'attending', - 'name' => 'attending', - 'options' => [ - [ - 'label' => 'Yes', - 'value' => 'yes', - ], - [ - 'label' => 'No', - 'value' => 'no', - ], - ], - 'validation' => 'required', - ], - [ - '$el' => 'div', - 'if' => '$get(attending).value === "yes"', - 'children' => $content, - ], - [ - '$formkit' => 'submit', - 'if' => '$get(attending).value === "no"', - 'label' => 'Submit', - 'disabled' => '$get(form).state.valid !== true', - ], - ]; - - return [ - '$cmp' => 'FormKit', - 'props' => [ - 'type' => 'form', - 'id' => 'form', - 'onSubmit' => '$submitForm', - 'plugins' => '$plugins', - 'actions' => false, - ], - 'children' => $content, - ]; + return $content; } public function content(array $content, ?Collection $fields = null): array diff --git a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php new file mode 100644 index 0000000000..31adf39373 --- /dev/null +++ b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php @@ -0,0 +1,57 @@ +generateContent($submissible); + + $content = [ + [ + '$formkit' => 'radio', + 'label' => 'Will you be attending?', + 'id' => 'attending', + 'name' => 'attending', + 'options' => [ + [ + 'label' => 'Yes', + 'value' => 'yes', + ], + [ + 'label' => 'No', + 'value' => 'no', + ], + ], + 'validation' => 'required', + ], + [ + '$el' => 'div', + 'if' => '$get(attending).value === "yes"', + 'children' => $content, + ], + [ + '$formkit' => 'submit', + 'if' => '$get(attending).value === "no"', + 'label' => 'Submit', + 'disabled' => '$get(form).state.valid !== true', + ], + ]; + + return [ + '$cmp' => 'FormKit', + 'props' => [ + 'type' => 'form', + 'id' => 'form', + 'onSubmit' => '$submitForm', + 'plugins' => '$plugins', + 'actions' => false, + ], + 'children' => $content, + ]; + } +} \ No newline at end of file diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index bc9d4fe1d2..898e656280 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -50,18 +50,18 @@ use AdvisingApp\MeetingCenter\Models\Event; use Illuminate\Support\Facades\Notification; use Symfony\Component\HttpFoundation\Response; -use AdvisingApp\Form\Actions\GenerateFormKitSchema; use AdvisingApp\MeetingCenter\Models\EventAttendee; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; use AdvisingApp\Form\Actions\GenerateSubmissibleValidation; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormSubmission; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; use AdvisingApp\IntegrationGoogleRecaptcha\Settings\GoogleRecaptchaSettings; +use AdvisingApp\MeetingCenter\Actions\GenerateEventRegistrationFormKitSchema; use AdvisingApp\MeetingCenter\Notifications\AuthenticateEventRegistrationFormNotification; class EventRegistrationWidgetController extends Controller { - public function view(GenerateFormKitSchema $generateSchema, Event $event): JsonResponse + public function view(GenerateEventRegistrationFormKitSchema $generateSchema, Event $event): JsonResponse { $form = $event->eventRegistrationForm; From 8a2c878853e0e9f15fa9e6479bd3ffba9df8241a Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 16:07:36 -0500 Subject: [PATCH 44/56] Fix bug with multistep Signed-off-by: Kevin Ullyott --- .../Pages/Concerns/HasSharedEventFormConfiguration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php index f3de80786e..15f123c68b 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php @@ -151,7 +151,7 @@ public function fieldBuilder(): TiptapEditor $form = $record instanceof EventRegistrationForm ? $record : $record->submissible; $formStep = $record instanceof EventRegistrationFormStep ? $record : null; - EventRegistrationFormStep::query() + EventRegistrationFormField::query() ->whereBelongsTo($form, 'submissible') ->when($formStep, fn (EloquentBuilder $query) => $query->whereBelongsTo($formStep, 'step')) ->delete(); From 3e348a2ad0c56498e83c6352e53a34880d57c75b Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 16:39:14 -0500 Subject: [PATCH 45/56] Init viewing event attendees Signed-off-by: Kevin Ullyott --- .../src/Enums/EventAttendeeStatus.php | 15 +++- .../src/Filament/Resources/EventResource.php | 12 +++ .../Pages/ManageEventAttendees.php | 88 +++++++++++++++++++ .../meeting-center/src/Models/Event.php | 6 ++ .../src/Models/EventAttendee.php | 6 ++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php diff --git a/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php b/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php index f84db2a022..ba6ad0a674 100644 --- a/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php +++ b/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php @@ -2,7 +2,10 @@ namespace AdvisingApp\MeetingCenter\Enums; -enum EventAttendeeStatus: string +use Filament\Support\Contracts\HasColor; +use Filament\Support\Contracts\HasLabel; + +enum EventAttendeeStatus: string implements HasColor, HasLabel { case Invited = 'invited'; @@ -19,4 +22,14 @@ public function getLabel(): ?string default => $this->name, }; } + + public function getColor(): string + { + return match ($this) { + self::Invited => 'info', + self::Pending => 'warning', + self::Attending => 'success', + self::NotAttending => 'danger', + }; + } } diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource.php b/app-modules/meeting-center/src/Filament/Resources/EventResource.php index 57e54bee16..7f258955d0 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource.php @@ -37,11 +37,13 @@ namespace AdvisingApp\MeetingCenter\Filament\Resources; use Filament\Resources\Resource; +use Filament\Resources\Pages\Page; use AdvisingApp\MeetingCenter\Models\Event; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\EditEvent; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\ViewEvent; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\ListEvents; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\CreateEvent; +use AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\ManageEventAttendees; class EventResource extends Resource { @@ -58,6 +60,15 @@ public static function getRelations(): array return []; } + public static function getRecordSubNavigation(Page $page): array + { + return $page->generateNavigationItems([ + ViewEvent::class, + EditEvent::class, + ManageEventAttendees::class, + ]); + } + public static function getPages(): array { return [ @@ -65,6 +76,7 @@ public static function getPages(): array 'create' => CreateEvent::route('/create'), 'view' => ViewEvent::route('/{record}'), 'edit' => EditEvent::route('/{record}/edit'), + 'manage-attendees' => ManageEventAttendees::route('/{record}/manage-attendees'), ]; } } diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php new file mode 100644 index 0000000000..3ccd98b991 --- /dev/null +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php @@ -0,0 +1,88 @@ + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + +namespace AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages; + +use Filament\Tables\Table; +use App\Filament\Columns\IdColumn; +use Filament\Tables\Columns\TextColumn; +use Filament\Resources\Pages\ManageRelatedRecords; +use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; + +class ManageEventAttendees extends ManageRelatedRecords +{ + protected static string $resource = EventResource::class; + + // TODO: Obsolete when there is no table, remove from Filament + protected static string $relationship = 'attendees'; + + protected static ?string $navigationLabel = 'Attendees'; + + protected static ?string $breadcrumb = 'Attendees'; + + protected static ?string $navigationIcon = 'heroicon-o-document-text'; + + public function table(Table $table): Table + { + return $table + ->columns([ + IdColumn::make(), + TextColumn::make('status') + ->badge(), + TextColumn::make('email'), + ]) + ->filters([]) + ->headerActions([]) + ->actions([ + //ViewAction::make() + // ->modalHeading(fn (SurveySubmission $record) => 'Submission Details: ' . $record->submitted_at->format('M j, Y H:i:s')) + // ->infolist(fn (SurveySubmission $record): ?array => ($record->author && $record->submissible->is_authenticated) ? [ + // Section::make('Authenticated author') + // ->schema([ + // TextEntry::make('author.' . $record->author::displayNameKey()) + // ->label('Name'), + // TextEntry::make('author.email') + // ->label('Email address'), + // ]) + // ->columns(2), + // ] : null) + // ->modalContent(fn (SurveySubmission $record) => view('survey::submission', ['submission' => $record])) + // ->visible(fn (SurveySubmission $record) => $record->submitted_at), + //DeleteAction::make(), + ]) + ->bulkActions([]); + } +} diff --git a/app-modules/meeting-center/src/Models/Event.php b/app-modules/meeting-center/src/Models/Event.php index e19a7706e9..4dba05b52f 100644 --- a/app-modules/meeting-center/src/Models/Event.php +++ b/app-modules/meeting-center/src/Models/Event.php @@ -38,6 +38,7 @@ use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\HasOne; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * @mixin IdeHelperEvent @@ -62,4 +63,9 @@ public function eventRegistrationForm(): HasOne { return $this->hasOne(EventRegistrationForm::class, 'event_id'); } + + public function attendees(): HasMany + { + return $this->hasMany(EventAttendee::class, 'event_id'); + } } diff --git a/app-modules/meeting-center/src/Models/EventAttendee.php b/app-modules/meeting-center/src/Models/EventAttendee.php index fab1a5c640..f3c957ad13 100644 --- a/app-modules/meeting-center/src/Models/EventAttendee.php +++ b/app-modules/meeting-center/src/Models/EventAttendee.php @@ -39,6 +39,7 @@ use App\Models\BaseModel; use App\Models\Attributes\NoPermissions; use Illuminate\Notifications\Notifiable; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; #[NoPermissions] @@ -58,4 +59,9 @@ class EventAttendee extends BaseModel protected $casts = [ 'status' => EventAttendeeStatus::class, ]; + + public function event(): BelongsTo + { + return $this->belongsTo(Event::class, 'event_id'); + } } From 0be7d34d5393e19e531465780f8f0dbe0c94ec69 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Thu, 28 Dec 2023 16:44:14 -0500 Subject: [PATCH 46/56] More work on Attendee Signed-off-by: Kevin Ullyott --- .../Pages/ManageEventAttendees.php | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php index 3ccd98b991..f64949509c 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php @@ -38,8 +38,12 @@ use Filament\Tables\Table; use App\Filament\Columns\IdColumn; +use Filament\Tables\Actions\ViewAction; use Filament\Tables\Columns\TextColumn; +use Filament\Infolists\Components\Section; +use Filament\Infolists\Components\TextEntry; use Filament\Resources\Pages\ManageRelatedRecords; +use AdvisingApp\MeetingCenter\Models\EventAttendee; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; class ManageEventAttendees extends ManageRelatedRecords @@ -67,21 +71,21 @@ public function table(Table $table): Table ->filters([]) ->headerActions([]) ->actions([ - //ViewAction::make() - // ->modalHeading(fn (SurveySubmission $record) => 'Submission Details: ' . $record->submitted_at->format('M j, Y H:i:s')) - // ->infolist(fn (SurveySubmission $record): ?array => ($record->author && $record->submissible->is_authenticated) ? [ - // Section::make('Authenticated author') - // ->schema([ - // TextEntry::make('author.' . $record->author::displayNameKey()) - // ->label('Name'), - // TextEntry::make('author.email') - // ->label('Email address'), - // ]) - // ->columns(2), - // ] : null) - // ->modalContent(fn (SurveySubmission $record) => view('survey::submission', ['submission' => $record])) - // ->visible(fn (SurveySubmission $record) => $record->submitted_at), - //DeleteAction::make(), + ViewAction::make() + ->modalHeading(fn (EventAttendee $record) => $record->event->title . ' - ' . $record->email) + ->infolist(fn (EventAttendee $record): array => [ + Section::make('Attendee Info') + ->schema([ + TextEntry::make('status') + ->label('Status') + ->badge(), + TextEntry::make('email') + ->label('Email address'), + ]) + ->columns(), + ]), + // TODO: Display this Attendees submissions + //->modalContent(fn (EventAttendee $record) => view('survey::submission', ['submission' => $record])), ]) ->bulkActions([]); } From 4c5c3f8bb2ffdccfd98670c9314d1ffc95357035 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Fri, 29 Dec 2023 13:59:21 -0500 Subject: [PATCH 47/56] Fix bug Signed-off-by: Kevin Ullyott --- .../src/Http/Controllers/EventRegistrationWidgetController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php index 898e656280..b1c816251e 100644 --- a/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php +++ b/app-modules/meeting-center/src/Http/Controllers/EventRegistrationWidgetController.php @@ -206,7 +206,7 @@ public function store( $data = $validator->validated(); if ($data['attending'] === 'yes') { - unset($data['recaptcha-token']); + unset($data['recaptcha-token'], $data['attending']); if ($form->is_wizard) { foreach ($form->steps as $step) { From 12b6131784d6d2125f54f21151247bc9293f0ea2 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Fri, 29 Dec 2023 14:57:22 -0500 Subject: [PATCH 48/56] Start displaying the attendee submission Signed-off-by: Kevin Ullyott --- ...ent-attendee-submissions-manager.blade.php | 3 + .../Pages/ManageEventAttendees.php | 4 ++ .../EventAttendeeSubmissionsManager.php | 60 +++++++++++++++++++ .../src/Models/EventAttendee.php | 6 ++ .../EventRegistrationFormSubmission.php | 45 -------------- .../MeetingCenterServiceProvider.php | 4 ++ 6 files changed, 77 insertions(+), 45 deletions(-) create mode 100644 app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php create mode 100644 app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php diff --git a/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php b/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php new file mode 100644 index 0000000000..c3fedc4aac --- /dev/null +++ b/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php @@ -0,0 +1,3 @@ +
+ {{ $this->table }} +
diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php index f64949509c..ef9922f12c 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php @@ -41,6 +41,7 @@ use Filament\Tables\Actions\ViewAction; use Filament\Tables\Columns\TextColumn; use Filament\Infolists\Components\Section; +use Filament\Infolists\Components\Livewire; use Filament\Infolists\Components\TextEntry; use Filament\Resources\Pages\ManageRelatedRecords; use AdvisingApp\MeetingCenter\Models\EventAttendee; @@ -83,6 +84,9 @@ public function table(Table $table): Table ->label('Email address'), ]) ->columns(), + // TODO: Look into Livewire/Filament bug that prevents us from passing the class here, requiring that we define it in the Service Provider + // TODO: Look into bug where, without lazy load, you have to click view twice to get the modal to show + Livewire::make('event-attendee-submissions-manager')->lazy(), ]), // TODO: Display this Attendees submissions //->modalContent(fn (EventAttendee $record) => view('survey::submission', ['submission' => $record])), diff --git a/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php b/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php new file mode 100644 index 0000000000..211f87bc04 --- /dev/null +++ b/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php @@ -0,0 +1,60 @@ +relationship(fn (): HasMany => $this->record->submissions()) + ->inverseRelationship('author') + ->columns([ + TextColumn::make('attendee_status') + ->badge(), + ]) + ->filters([ + // ... + ]) + ->actions([ + ViewAction::make() + ->modalHeading(fn (EventRegistrationFormSubmission $record) => 'Submission Details: ' . $record->submitted_at->format('M j, Y H:i:s')) + ->infolist(fn (EventRegistrationFormSubmission $record): array => [ + Section::make('Authenticated author') + ->schema([ + TextEntry::make('author.email') + ->label('Email Address'), + ]) + ->columns(), + ]), + //->modalContent(fn (FormSubmission $record) => view('form::submission', ['submission' => $record])), + ]) + ->bulkActions([ + // ... + ]); + } +} diff --git a/app-modules/meeting-center/src/Models/EventAttendee.php b/app-modules/meeting-center/src/Models/EventAttendee.php index f3c957ad13..3564fc7334 100644 --- a/app-modules/meeting-center/src/Models/EventAttendee.php +++ b/app-modules/meeting-center/src/Models/EventAttendee.php @@ -39,6 +39,7 @@ use App\Models\BaseModel; use App\Models\Attributes\NoPermissions; use Illuminate\Notifications\Notifiable; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; @@ -64,4 +65,9 @@ public function event(): BelongsTo { return $this->belongsTo(Event::class, 'event_id'); } + + public function submissions(): HasMany + { + return $this->hasMany(EventRegistrationFormSubmission::class, 'event_attendee_id'); + } } diff --git a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php index 2c6aba5124..75d629a0e1 100644 --- a/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php +++ b/app-modules/meeting-center/src/Models/EventRegistrationFormSubmission.php @@ -38,8 +38,6 @@ use App\Models\User; use AdvisingApp\Form\Models\Submission; -use Illuminate\Database\Eloquent\Builder; -use AdvisingApp\Form\Enums\FormSubmissionStatus; use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -92,47 +90,4 @@ public function author(): BelongsTo { return $this->belongsTo(EventAttendee::class, 'event_attendee_id'); } - - public function deliverRequest(): void - { - $this->request_method->deliver($this); - } - - public function scopeRequested(Builder $query): Builder - { - return $query->notSubmitted()->notCanceled(); - } - - public function scopeSubmitted(Builder $query): Builder - { - return $query->whereNotNull('submitted_at'); - } - - public function scopeCanceled(Builder $query): Builder - { - return $query->notSubmitted()->whereNotNull('canceled_at'); - } - - public function scopeNotSubmitted(Builder $query): Builder - { - return $query->whereNull('submitted_at'); - } - - public function scopeNotCanceled(Builder $query): Builder - { - return $query->whereNull('canceled_at'); - } - - public function getStatus(): FormSubmissionStatus - { - if ($this->submitted_at) { - return FormSubmissionStatus::Submitted; - } - - if ($this->canceled_at) { - return FormSubmissionStatus::Canceled; - } - - return FormSubmissionStatus::Requested; - } } diff --git a/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php b/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php index bc5e36b29c..e3dc80d32a 100644 --- a/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php +++ b/app-modules/meeting-center/src/Providers/MeetingCenterServiceProvider.php @@ -37,6 +37,7 @@ namespace AdvisingApp\MeetingCenter\Providers; use Filament\Panel; +use Livewire\Livewire; use Illuminate\Support\ServiceProvider; use AdvisingApp\MeetingCenter\Models\Event; use Illuminate\Console\Scheduling\Schedule; @@ -53,6 +54,7 @@ use AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormField; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormSubmission; +use AdvisingApp\MeetingCenter\Livewire\EventAttendeeSubmissionsManager; use AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication; class MeetingCenterServiceProvider extends ServiceProvider @@ -86,6 +88,8 @@ public function boot(): void $this->registerRolesAndPermissions(); $this->registerObservers(); + + Livewire::component('event-attendee-submissions-manager', EventAttendeeSubmissionsManager::class); } protected function registerRolesAndPermissions(): void From 37de56e14709d303eb8e559db1b3a42d63693f14 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Fri, 29 Dec 2023 15:16:46 -0500 Subject: [PATCH 49/56] Display an attendees submissions Signed-off-by: Kevin Ullyott --- .../event-registration-submission.blade.php | 55 +++++++++++++++++++ .../Pages/ManageEventAttendees.php | 17 +++--- .../EventAttendeeSubmissionsManager.php | 23 ++++---- 3 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 app-modules/meeting-center/resources/views/event-registration-submission.blade.php diff --git a/app-modules/meeting-center/resources/views/event-registration-submission.blade.php b/app-modules/meeting-center/resources/views/event-registration-submission.blade.php new file mode 100644 index 0000000000..2756746379 --- /dev/null +++ b/app-modules/meeting-center/resources/views/event-registration-submission.blade.php @@ -0,0 +1,55 @@ +{{-- + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +--}} + +
+ @if ($submission->submissible->is_wizard) + @foreach ($submission->submissible->steps as $step) + + + {{ $step->label }} + + + + + @endforeach + @else + + @endif +
diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php index ef9922f12c..a228570e01 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php @@ -40,7 +40,7 @@ use App\Filament\Columns\IdColumn; use Filament\Tables\Actions\ViewAction; use Filament\Tables\Columns\TextColumn; -use Filament\Infolists\Components\Section; +use Filament\Infolists\Components\Fieldset; use Filament\Infolists\Components\Livewire; use Filament\Infolists\Components\TextEntry; use Filament\Resources\Pages\ManageRelatedRecords; @@ -75,7 +75,7 @@ public function table(Table $table): Table ViewAction::make() ->modalHeading(fn (EventAttendee $record) => $record->event->title . ' - ' . $record->email) ->infolist(fn (EventAttendee $record): array => [ - Section::make('Attendee Info') + Fieldset::make('Attendee Info') ->schema([ TextEntry::make('status') ->label('Status') @@ -84,12 +84,15 @@ public function table(Table $table): Table ->label('Email address'), ]) ->columns(), - // TODO: Look into Livewire/Filament bug that prevents us from passing the class here, requiring that we define it in the Service Provider - // TODO: Look into bug where, without lazy load, you have to click view twice to get the modal to show - Livewire::make('event-attendee-submissions-manager')->lazy(), + + Fieldset::make('Attendee Submissions') + ->schema([ + // TODO: Look into Livewire/Filament bug that prevents us from passing the class here, requiring that we define it in the Service Provider + // TODO: Look into bug where, without lazy load, you have to click view twice to get the modal to show + Livewire::make('event-attendee-submissions-manager')->lazy() + ->columnSpanFull(), + ]), ]), - // TODO: Display this Attendees submissions - //->modalContent(fn (EventAttendee $record) => view('survey::submission', ['submission' => $record])), ]) ->bulkActions([]); } diff --git a/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php b/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php index 211f87bc04..91a41825ad 100644 --- a/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php +++ b/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php @@ -34,27 +34,30 @@ public function table(Table $table): Table ->relationship(fn (): HasMany => $this->record->submissions()) ->inverseRelationship('author') ->columns([ + TextColumn::make('submitted_at') + ->label('Submitted At') + ->dateTime() + ->sortable(), TextColumn::make('attendee_status') + ->label('Submission Status') ->badge(), ]) - ->filters([ - // ... - ]) + ->defaultSort('submitted_at', 'desc') ->actions([ ViewAction::make() ->modalHeading(fn (EventRegistrationFormSubmission $record) => 'Submission Details: ' . $record->submitted_at->format('M j, Y H:i:s')) ->infolist(fn (EventRegistrationFormSubmission $record): array => [ - Section::make('Authenticated author') + Section::make('Metadata') ->schema([ TextEntry::make('author.email') - ->label('Email Address'), + ->label('Author Email Address'), + TextEntry::make('attendee_status') + ->label('Submission Status') + ->badge(), ]) ->columns(), - ]), - //->modalContent(fn (FormSubmission $record) => view('form::submission', ['submission' => $record])), - ]) - ->bulkActions([ - // ... + ]) + ->modalContent(fn (EventRegistrationFormSubmission $record) => view('meeting-center::event-registration-submission', ['submission' => $record])), ]); } } From f71c2e7218d11d015cb2368486213e2b288b8a22 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Fri, 29 Dec 2023 15:53:14 -0500 Subject: [PATCH 50/56] Relate a Student or Prospect to an EventAttendee Signed-off-by: Kevin Ullyott --- .../Pages/ManageEventAttendees.php | 29 +++++++++++++++++++ .../src/Models/EventAttendee.php | 20 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php index a228570e01..dc7cc511f5 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/ManageEventAttendees.php @@ -40,12 +40,17 @@ use App\Filament\Columns\IdColumn; use Filament\Tables\Actions\ViewAction; use Filament\Tables\Columns\TextColumn; +use AdvisingApp\Prospect\Models\Prospect; use Filament\Infolists\Components\Fieldset; use Filament\Infolists\Components\Livewire; use Filament\Infolists\Components\TextEntry; +use AdvisingApp\StudentDataModel\Models\Student; +use Filament\Infolists\Components\RepeatableEntry; use Filament\Resources\Pages\ManageRelatedRecords; use AdvisingApp\MeetingCenter\Models\EventAttendee; +use AdvisingApp\Prospect\Filament\Resources\ProspectResource; use AdvisingApp\MeetingCenter\Filament\Resources\EventResource; +use AdvisingApp\StudentDataModel\Filament\Resources\StudentResource; class ManageEventAttendees extends ManageRelatedRecords { @@ -85,6 +90,30 @@ public function table(Table $table): Table ]) ->columns(), + Fieldset::make('Relations') + ->schema([ + RepeatableEntry::make('prospects') + ->schema([ + TextEntry::make(Prospect::displayNameKey()) + ->label('Name') + ->color('primary') + ->url(fn (Prospect $record): string => ProspectResource::getUrl('view', ['record' => $record])), + ]) + ->columns() + ->visible(fn (EventAttendee $record): bool => $record->prospects->isNotEmpty()), + RepeatableEntry::make('students') + ->schema([ + TextEntry::make(Student::displayNameKey()) + ->label('Name') + ->color('primary') + ->url(fn (Student $record): string => StudentResource::getUrl('view', ['record' => $record])), + ]) + ->columns() + ->visible(fn (EventAttendee $record): bool => $record->students->isNotEmpty()), + ]) + ->visible(fn (EventAttendee $record): bool => $record->prospects->isNotEmpty() || $record->students->isNotEmpty()) + ->columns(), + Fieldset::make('Attendee Submissions') ->schema([ // TODO: Look into Livewire/Filament bug that prevents us from passing the class here, requiring that we define it in the Service Provider diff --git a/app-modules/meeting-center/src/Models/EventAttendee.php b/app-modules/meeting-center/src/Models/EventAttendee.php index 3564fc7334..9590bae852 100644 --- a/app-modules/meeting-center/src/Models/EventAttendee.php +++ b/app-modules/meeting-center/src/Models/EventAttendee.php @@ -39,6 +39,8 @@ use App\Models\BaseModel; use App\Models\Attributes\NoPermissions; use Illuminate\Notifications\Notifiable; +use AdvisingApp\Prospect\Models\Prospect; +use AdvisingApp\StudentDataModel\Models\Student; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; use AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus; @@ -70,4 +72,22 @@ public function submissions(): HasMany { return $this->hasMany(EventRegistrationFormSubmission::class, 'event_attendee_id'); } + + public function prospects(): HasMany + { + return $this->hasMany( + related: Prospect::class, + foreignKey: 'email', + localKey: 'email', + ); + } + + public function students(): HasMany + { + return $this->hasMany( + related: Student::class, + foreignKey: 'email', + localKey: 'email', + ); + } } From 5ae60bb5706d2f03eac48382f671f342877d4470 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Fri, 29 Dec 2023 16:39:38 -0500 Subject: [PATCH 51/56] Clear out unneded columns Signed-off-by: Kevin Ullyott --- ...94229_create_event_registration_form_submissions_table.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php b/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php index 2b362933c9..af7df1dc37 100644 --- a/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php +++ b/app-modules/meeting-center/database/migrations/2023_12_27_194229_create_event_registration_form_submissions_table.php @@ -48,10 +48,6 @@ public function up(): void $table->foreignUuid('event_attendee_id')->constrained('event_attendees')->cascadeOnDelete(); $table->string('attendee_status'); $table->timestamp('submitted_at')->nullable(); - $table->timestamp('canceled_at')->nullable(); - $table->string('request_method')->nullable(); - $table->text('request_note')->nullable(); - $table->foreignUuid('requester_id')->nullable()->constrained('users')->nullOnDelete(); $table->timestamps(); $table->softDeletes(); From 3defeb9962bd453c1850fa8c49388f418f8039af Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Fri, 29 Dec 2023 16:44:03 -0500 Subject: [PATCH 52/56] composer update Signed-off-by: Kevin Ullyott --- composer.lock | 145 +++++++++++++++++++++++++++++++------------------- 1 file changed, 90 insertions(+), 55 deletions(-) diff --git a/composer.lock b/composer.lock index 029ba3e12f..ba8789147b 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": "a7c988d45a8bf04ea377069a6dd7b23a", + "content-hash": "19b34ef965a1ec4aa7ec0deb038e20bd", "packages": [ { "name": "amphp/amp", @@ -559,16 +559,16 @@ }, { "name": "awcodes/filament-tiptap-editor", - "version": "v3.2.17", + "version": "v3.2.18", "source": { "type": "git", "url": "https://github.com/awcodes/filament-tiptap-editor.git", - "reference": "0c56c96d6dddad9b61ad36aaa500cdb04dd5dd9f" + "reference": "7de016e723ba62908f979a39204955e1801b0967" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/awcodes/filament-tiptap-editor/zipball/0c56c96d6dddad9b61ad36aaa500cdb04dd5dd9f", - "reference": "0c56c96d6dddad9b61ad36aaa500cdb04dd5dd9f", + "url": "https://api.github.com/repos/awcodes/filament-tiptap-editor/zipball/7de016e723ba62908f979a39204955e1801b0967", + "reference": "7de016e723ba62908f979a39204955e1801b0967", "shasum": "" }, "require": { @@ -630,7 +630,7 @@ ], "support": { "issues": "https://github.com/awcodes/filament-tiptap-editor/issues", - "source": "https://github.com/awcodes/filament-tiptap-editor/tree/v3.2.17" + "source": "https://github.com/awcodes/filament-tiptap-editor/tree/v3.2.18" }, "funding": [ { @@ -638,7 +638,7 @@ "type": "github" } ], - "time": "2023-12-27T19:10:56+00:00" + "time": "2023-12-28T20:05:06+00:00" }, { "name": "aws/aws-crt-php", @@ -755,16 +755,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.295.2", + "version": "3.295.4", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "7e8f68580954a01cf9c8f2abd4f4db52ebcb7b73" + "reference": "2372661db989fe4229abd95f4434b37252076d58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7e8f68580954a01cf9c8f2abd4f4db52ebcb7b73", - "reference": "7e8f68580954a01cf9c8f2abd4f4db52ebcb7b73", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2372661db989fe4229abd95f4434b37252076d58", + "reference": "2372661db989fe4229abd95f4434b37252076d58", "shasum": "" }, "require": { @@ -844,9 +844,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.295.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.295.4" }, - "time": "2023-12-27T19:06:10+00:00" + "time": "2023-12-29T19:07:49+00:00" }, { "name": "barryvdh/laravel-debugbar", @@ -2379,6 +2379,41 @@ "relative": true } }, + { + "name": "canyon-gbs/inventory-management", + "version": "1.0", + "dist": { + "type": "path", + "url": "app-modules/inventory-management", + "reference": "16210c789f3a6d5a4b14ce0db3a17f5cdc4f6e48" + }, + "require": { + "filament/filament": "^3.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "AdvisingApp\\InventoryManagement\\Providers\\InventoryManagementServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "AdvisingApp\\InventoryManagement\\": "src/", + "AdvisingApp\\InventoryManagement\\Tests\\": "tests/", + "AdvisingApp\\InventoryManagement\\Database\\Factories\\": "database/factories/", + "AdvisingApp\\InventoryManagement\\Database\\Seeders\\": "database/seeders/" + } + }, + "license": [ + "proprietary" + ], + "transport-options": { + "symlink": true, + "relative": true + } + }, { "name": "carbonphp/carbon-doctrine-types", "version": "2.1.0", @@ -4071,7 +4106,7 @@ }, { "name": "filament/actions", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", @@ -4122,7 +4157,7 @@ }, { "name": "filament/filament", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", @@ -4187,7 +4222,7 @@ }, { "name": "filament/forms", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", @@ -4243,7 +4278,7 @@ }, { "name": "filament/infolists", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", @@ -4294,7 +4329,7 @@ }, { "name": "filament/notifications", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", @@ -4346,7 +4381,7 @@ }, { "name": "filament/spatie-laravel-media-library-plugin", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-media-library-plugin.git", @@ -4383,7 +4418,7 @@ }, { "name": "filament/spatie-laravel-settings-plugin", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-settings-plugin.git", @@ -4430,7 +4465,7 @@ }, { "name": "filament/support", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", @@ -4487,16 +4522,16 @@ }, { "name": "filament/tables", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "ea8518eeaf15111b4dbd7438a8a00a3c3ab48c67" + "reference": "e0701467097f6a82b235ad9f31e3c30ae1035118" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/ea8518eeaf15111b4dbd7438a8a00a3c3ab48c67", - "reference": "ea8518eeaf15111b4dbd7438a8a00a3c3ab48c67", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/e0701467097f6a82b235ad9f31e3c30ae1035118", + "reference": "e0701467097f6a82b235ad9f31e3c30ae1035118", "shasum": "" }, "require": { @@ -4536,20 +4571,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-28T15:54:29+00:00" + "time": "2023-12-28T17:31:59+00:00" }, { "name": "filament/widgets", - "version": "v3.1.30", + "version": "v3.1.31", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", - "reference": "7195d2fe7d12a9b9595fa445a4dbedd6d7714836" + "reference": "26240d5f7d6aec4dd9c5987880b4deb5f9000ddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/widgets/zipball/7195d2fe7d12a9b9595fa445a4dbedd6d7714836", - "reference": "7195d2fe7d12a9b9595fa445a4dbedd6d7714836", + "url": "https://api.github.com/repos/filamentphp/widgets/zipball/26240d5f7d6aec4dd9c5987880b4deb5f9000ddd", + "reference": "26240d5f7d6aec4dd9c5987880b4deb5f9000ddd", "shasum": "" }, "require": { @@ -4580,7 +4615,7 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2023-12-24T21:17:06+00:00" + "time": "2023-12-28T17:31:57+00:00" }, { "name": "firebase/php-jwt", @@ -10161,16 +10196,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.34", + "version": "3.0.35", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "56c79f16a6ae17e42089c06a2144467acc35348a" + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a", - "reference": "56c79f16a6ae17e42089c06a2144467acc35348a", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4b1827beabce71953ca479485c0ae9c51287f2fe", + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe", "shasum": "" }, "require": { @@ -10251,7 +10286,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.34" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.35" }, "funding": [ { @@ -10267,7 +10302,7 @@ "type": "tidelift" } ], - "time": "2023-11-27T11:13:31+00:00" + "time": "2023-12-29T01:59:53+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -17148,16 +17183,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.42.0", + "version": "v3.44.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "632ef1be3447a9b890bef06147475facee535d0f" + "reference": "5445834057a744c1a434ed60fcac566b4de3a0f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/632ef1be3447a9b890bef06147475facee535d0f", - "reference": "632ef1be3447a9b890bef06147475facee535d0f", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5445834057a744c1a434ed60fcac566b4de3a0f2", + "reference": "5445834057a744c1a434ed60fcac566b4de3a0f2", "shasum": "" }, "require": { @@ -17187,7 +17222,7 @@ "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", - "phpunit/phpunit": "^9.6", + "phpunit/phpunit": "^9.6 || ^10.5.5", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { @@ -17226,7 +17261,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.42.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.44.0" }, "funding": [ { @@ -17234,7 +17269,7 @@ "type": "github" } ], - "time": "2023-12-24T14:38:51+00:00" + "time": "2023-12-29T20:21:16+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -20765,28 +20800,28 @@ }, { "name": "ta-tikoma/phpunit-architecture-test", - "version": "0.7.5", + "version": "0.7.6", "source": { "type": "git", "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", - "reference": "9eb08437e8f0c0c75cc947a373cf49672c335827" + "reference": "a252cd9488fd62f3c8c6cafa303b1b96e9df24e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/9eb08437e8f0c0c75cc947a373cf49672c335827", - "reference": "9eb08437e8f0c0c75cc947a373cf49672c335827", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/a252cd9488fd62f3c8c6cafa303b1b96e9df24e0", + "reference": "a252cd9488fd62f3c8c6cafa303b1b96e9df24e0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.15.4", + "nikic/php-parser": "^4.18.0", "php": "^8.1.0", "phpdocumentor/reflection-docblock": "^5.3.0", - "phpunit/phpunit": "^10.1.1", - "symfony/finder": "^6.2.7 || ^7.0.0" + "phpunit/phpunit": "^10.5.5", + "symfony/finder": "^6.4.0 || ^7.0.0" }, "require-dev": { - "laravel/pint": "^1.9.0", - "phpstan/phpstan": "^1.10.13" + "laravel/pint": "^1.13.7", + "phpstan/phpstan": "^1.10.50" }, "type": "library", "autoload": { @@ -20818,9 +20853,9 @@ ], "support": { "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", - "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.7.5" + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.7.6" }, - "time": "2023-10-12T15:31:50+00:00" + "time": "2023-12-29T13:14:58+00:00" }, { "name": "theseer/tokenizer", From f93ac5d8328c3ff92fac981d4fe22c5b002f572e Mon Sep 17 00:00:00 2001 From: Orrison Date: Fri, 29 Dec 2023 21:45:41 +0000 Subject: [PATCH 53/56] chore: fix enforcement of copyright on all files --- ...ent-attendee-submissions-manager.blade.php | 33 ++++++++++++++++++ ...GenerateEventRegistrationFormKitSchema.php | 34 +++++++++++++++++++ .../src/Enums/EventAttendeeStatus.php | 34 +++++++++++++++++++ .../HasSharedEventFormConfiguration.php | 34 +++++++++++++++++++ .../EventAttendeeSubmissionsManager.php | 34 +++++++++++++++++++ 5 files changed, 169 insertions(+) diff --git a/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php b/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php index c3fedc4aac..9c8071e9c4 100644 --- a/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php +++ b/app-modules/meeting-center/resources/views/livewire/event-attendee-submissions-manager.blade.php @@ -1,3 +1,36 @@ +{{-- + + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +--}}
{{ $this->table }}
diff --git a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php index 31adf39373..abea705568 100644 --- a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php +++ b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\MeetingCenter\Actions; use AdvisingApp\Form\Models\Submissible; diff --git a/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php b/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php index ba6ad0a674..407f84ae5e 100644 --- a/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php +++ b/app-modules/meeting-center/src/Enums/EventAttendeeStatus.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\MeetingCenter\Enums; use Filament\Support\Contracts\HasColor; diff --git a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php index 15f123c68b..fb5f1f5ce4 100644 --- a/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php +++ b/app-modules/meeting-center/src/Filament/Resources/EventResource/Pages/Concerns/HasSharedEventFormConfiguration.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\MeetingCenter\Filament\Resources\EventResource\Pages\Concerns; use App\Models\User; diff --git a/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php b/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php index 91a41825ad..a93aecee71 100644 --- a/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php +++ b/app-modules/meeting-center/src/Livewire/EventAttendeeSubmissionsManager.php @@ -1,5 +1,39 @@ + + Copyright © 2022-2023, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ + namespace AdvisingApp\MeetingCenter\Livewire; use Livewire\Component; From b25e780ade0ce4d0b882cc1b8da45a5c6ce61292 Mon Sep 17 00:00:00 2001 From: joelicatajr Date: Fri, 29 Dec 2023 21:49:05 +0000 Subject: [PATCH 54/56] chore: fix code style --- .../src/Actions/GenerateEventRegistrationFormKitSchema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php index abea705568..49ea7c3720 100644 --- a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php +++ b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php @@ -88,4 +88,4 @@ public function __invoke(Submissible $submissible): array 'children' => $content, ]; } -} \ No newline at end of file +} From 8d495f2d636c7cfd7875b693e34b954dad2e2679 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Tue, 2 Jan 2024 12:02:17 -0500 Subject: [PATCH 55/56] PR Feedback Signed-off-by: Kevin Ullyott --- .../src/Actions/GenerateFormKitSchema.php | 60 +++++++++-------- .../src/Models/SubmissibleAuthentication.php | 3 +- app-modules/form/src/Models/Submission.php | 3 +- ...GenerateEventRegistrationFormKitSchema.php | 64 +++++++++---------- 4 files changed, 61 insertions(+), 69 deletions(-) diff --git a/app-modules/form/src/Actions/GenerateFormKitSchema.php b/app-modules/form/src/Actions/GenerateFormKitSchema.php index 42168bffb5..f51dbc2029 100644 --- a/app-modules/form/src/Actions/GenerateFormKitSchema.php +++ b/app-modules/form/src/Actions/GenerateFormKitSchema.php @@ -45,8 +45,6 @@ class GenerateFormKitSchema { public function __invoke(Submissible $submissible): array { - $content = $this->generateContent($submissible); - return [ '$cmp' => 'FormKit', 'props' => [ @@ -56,38 +54,10 @@ public function __invoke(Submissible $submissible): array 'plugins' => '$plugins', 'actions' => false, ], - 'children' => $content, + 'children' => $this->generateContent($submissible), ]; } - public function generateContent(Submissible $submissible): array - { - if ($submissible->is_wizard) { - $submissible->loadMissing([ - 'steps' => [ - 'fields', - ], - ]); - - $content = $this->wizardContent($submissible); - } else { - $submissible->loadMissing([ - 'fields', - ]); - - $content = [ - ...$this->content($submissible->content['content'] ?? [], $submissible->fields->keyBy('id')), - [ - '$formkit' => 'submit', - 'label' => 'Submit', - 'disabled' => '$get(form).state.valid !== true', - ], - ]; - } - - return $content; - } - public function content(array $content, ?Collection $fields = null): array { $blocks = FormFieldBlockRegistry::keyByType(); @@ -278,4 +248,32 @@ public function wizardContent(Submissible $submissible): array ], ]; } + + protected function generateContent(Submissible $submissible): array + { + if ($submissible->is_wizard) { + $submissible->loadMissing([ + 'steps' => [ + 'fields', + ], + ]); + + $content = $this->wizardContent($submissible); + } else { + $submissible->loadMissing([ + 'fields', + ]); + + $content = [ + ...$this->content($submissible->content['content'] ?? [], $submissible->fields->keyBy('id')), + [ + '$formkit' => 'submit', + 'label' => 'Submit', + 'disabled' => '$get(form).state.valid !== true', + ], + ]; + } + + return $content; + } } diff --git a/app-modules/form/src/Models/SubmissibleAuthentication.php b/app-modules/form/src/Models/SubmissibleAuthentication.php index b5a0360f6f..3d6bb26158 100644 --- a/app-modules/form/src/Models/SubmissibleAuthentication.php +++ b/app-modules/form/src/Models/SubmissibleAuthentication.php @@ -41,7 +41,6 @@ use App\Models\Attributes\NoPermissions; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\MassPrunable; -use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\BelongsTo; /** @@ -66,7 +65,7 @@ public function prunable(): Builder ->where('created_at', '<', now()->subMonth()); } - public function author(): MorphTo|BelongsTo + public function author(): BelongsTo { return $this->morphTo(); } diff --git a/app-modules/form/src/Models/Submission.php b/app-modules/form/src/Models/Submission.php index 0816268c2e..86f3e41f3e 100644 --- a/app-modules/form/src/Models/Submission.php +++ b/app-modules/form/src/Models/Submission.php @@ -40,7 +40,6 @@ use AdvisingApp\Prospect\Models\Prospect; use Illuminate\Database\Eloquent\Collection; use AdvisingApp\StudentDataModel\Models\Student; -use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -55,7 +54,7 @@ abstract public function submissible(): BelongsTo; abstract public function fields(): BelongsToMany; - public function author(): MorphTo|BelongsTo + public function author(): BelongsTo { return $this ->morphTo('author'); diff --git a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php index 49ea7c3720..b9646558fb 100644 --- a/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php +++ b/app-modules/meeting-center/src/Actions/GenerateEventRegistrationFormKitSchema.php @@ -43,39 +43,6 @@ class GenerateEventRegistrationFormKitSchema extends GenerateFormKitSchema { public function __invoke(Submissible $submissible): array { - $content = $this->generateContent($submissible); - - $content = [ - [ - '$formkit' => 'radio', - 'label' => 'Will you be attending?', - 'id' => 'attending', - 'name' => 'attending', - 'options' => [ - [ - 'label' => 'Yes', - 'value' => 'yes', - ], - [ - 'label' => 'No', - 'value' => 'no', - ], - ], - 'validation' => 'required', - ], - [ - '$el' => 'div', - 'if' => '$get(attending).value === "yes"', - 'children' => $content, - ], - [ - '$formkit' => 'submit', - 'if' => '$get(attending).value === "no"', - 'label' => 'Submit', - 'disabled' => '$get(form).state.valid !== true', - ], - ]; - return [ '$cmp' => 'FormKit', 'props' => [ @@ -85,7 +52,36 @@ public function __invoke(Submissible $submissible): array 'plugins' => '$plugins', 'actions' => false, ], - 'children' => $content, + 'children' => [ + [ + '$formkit' => 'radio', + 'label' => 'Will you be attending?', + 'id' => 'attending', + 'name' => 'attending', + 'options' => [ + [ + 'label' => 'Yes', + 'value' => 'yes', + ], + [ + 'label' => 'No', + 'value' => 'no', + ], + ], + 'validation' => 'required', + ], + [ + '$el' => 'div', + 'if' => '$get(attending).value === "yes"', + 'children' => $this->generateContent($submissible), + ], + [ + '$formkit' => 'submit', + 'if' => '$get(attending).value === "no"', + 'label' => 'Submit', + 'disabled' => '$get(form).state.valid !== true', + ], + ], ]; } } From 8a3fb317666c9d364f0f2e45bdb926330b9c2887 Mon Sep 17 00:00:00 2001 From: Kevin Ullyott Date: Wed, 3 Jan 2024 09:23:32 -0500 Subject: [PATCH 56/56] Regenerate the helper file Signed-off-by: Kevin Ullyott --- _ide_helper_models.php | 118 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/_ide_helper_models.php b/_ide_helper_models.php index 520c0c5be7..1e43672ec5 100644 --- a/_ide_helper_models.php +++ b/_ide_helper_models.php @@ -832,6 +832,8 @@ class IdeHelperAudit {} * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $deleted_at + * @property-read \Illuminate\Database\Eloquent\Collection $audits + * @property-read int|null $audits_count * @property-read \App\Models\User $user * @method static \Illuminate\Database\Eloquent\Builder|License newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|License newQuery() @@ -2422,6 +2424,9 @@ class IdeHelperCalendarEvent {} * @property \Illuminate\Support\Carbon $ends_at * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $attendees + * @property-read int|null $attendees_count + * @property-read \AdvisingApp\MeetingCenter\Models\EventRegistrationForm|null $eventRegistrationForm * @method static \AdvisingApp\MeetingCenter\Database\Factories\EventFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|Event newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Event newQuery() @@ -2441,6 +2446,119 @@ class IdeHelperCalendarEvent {} class IdeHelperEvent {} } +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\EventAttendee + * + * @property \AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus $status + * @property-read \AdvisingApp\MeetingCenter\Models\Event|null $event + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read int|null $notifications_count + * @property-read \Illuminate\Database\Eloquent\Collection $prospects + * @property-read int|null $prospects_count + * @property-read \Illuminate\Database\Eloquent\Collection $students + * @property-read int|null $students_count + * @property-read \Illuminate\Database\Eloquent\Collection $submissions + * @property-read int|null $submissions_count + * @method static \Illuminate\Database\Eloquent\Builder|EventAttendee newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventAttendee newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventAttendee query() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEventAttendee {} +} + +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\EventRegistrationForm + * + * @property \AdvisingApp\Form\Enums\Rounding $rounding + * @property-read \AdvisingApp\MeetingCenter\Models\Event|null $event + * @property-read \Illuminate\Database\Eloquent\Collection $fields + * @property-read int|null $fields_count + * @property-read \Illuminate\Database\Eloquent\Collection $steps + * @property-read int|null $steps_count + * @property-read \Illuminate\Database\Eloquent\Collection $submissions + * @property-read int|null $submissions_count + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationForm newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationForm newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationForm onlyTrashed() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationForm query() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationForm withTrashed() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationForm withoutTrashed() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEventRegistrationForm {} +} + +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\EventRegistrationFormAuthentication + * + * @property-read EventRegistrationForm $submissible + * @property-read \AdvisingApp\MeetingCenter\Models\EventAttendee|null $author + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormAuthentication newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormAuthentication newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormAuthentication query() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEventRegistrationFormAuthentication {} +} + +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\EventRegistrationFormField + * + * @property-read \AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep $step + * @property-read \AdvisingApp\MeetingCenter\Models\EventRegistrationForm $submissible + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormField newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormField newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormField query() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEventRegistrationFormField {} +} + +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\EventRegistrationFormStep + * + * @property-read \Illuminate\Database\Eloquent\Collection $fields + * @property-read int|null $fields_count + * @property-read \AdvisingApp\MeetingCenter\Models\EventRegistrationForm $submissible + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormStep newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormStep newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormStep query() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEventRegistrationFormStep {} +} + +namespace AdvisingApp\MeetingCenter\Models{ +/** + * AdvisingApp\MeetingCenter\Models\EventRegistrationFormSubmission + * + * @property \AdvisingApp\Form\Enums\FormSubmissionRequestDeliveryMethod $request_method + * @property \AdvisingApp\MeetingCenter\Enums\EventAttendeeStatus $attendee_status + * @property-read \AdvisingApp\MeetingCenter\Models\EventAttendee|null $author + * @property-read \Illuminate\Database\Eloquent\Collection $fields + * @property-read int|null $fields_count + * @property-read \App\Models\User $requester + * @property-read \AdvisingApp\MeetingCenter\Models\EventRegistrationForm $submissible + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormSubmission newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormSubmission newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|EventRegistrationFormSubmission query() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperEventRegistrationFormSubmission {} +} + namespace AdvisingApp\Notification\Models{ /** * AdvisingApp\Notification\Models\OutboundDeliverable