diff --git a/_ide_helper_models.php b/_ide_helper_models.php index b4055344dd..bc0b9c0796 100644 --- a/_ide_helper_models.php +++ b/_ide_helper_models.php @@ -456,6 +456,7 @@ class IdeHelperApplication {} * @property \Illuminate\Support\Carbon|null $updated_at * @property-read \Illuminate\Database\Eloquent\Model|\Eloquent $author * @property-read \Assist\Application\Models\Application $submissible + * @method static \Assist\Application\Database\Factories\ApplicationAuthenticationFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|ApplicationAuthentication newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|ApplicationAuthentication newQuery() * @method static \Illuminate\Database\Eloquent\Builder|ApplicationAuthentication query() @@ -2457,12 +2458,12 @@ class IdeHelperServiceRequestAssignment {} * Assist\ServiceManagement\Models\ServiceRequestHistory * * @property string $id - * @property string|null $service_request_id + * @property string $service_request_id * @property array $original_values * @property array $new_values * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at - * @property-read \Assist\ServiceManagement\Models\ServiceRequest|null $serviceRequest + * @property-read \Assist\ServiceManagement\Models\ServiceRequest $serviceRequest * @method static \Assist\ServiceManagement\Database\Factories\ServiceRequestHistoryFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|ServiceRequestHistory newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|ServiceRequestHistory newQuery() diff --git a/app-modules/application/database/factories/ApplicationAuthenticationFactory.php b/app-modules/application/database/factories/ApplicationAuthenticationFactory.php new file mode 100644 index 0000000000..9091aca3e2 --- /dev/null +++ b/app-modules/application/database/factories/ApplicationAuthenticationFactory.php @@ -0,0 +1,74 @@ + + + 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 Assist\Application\Database\Factories; + +use Assist\Prospect\Models\Prospect; +use Illuminate\Support\Facades\Hash; +use Assist\Application\Models\Application; +use Assist\AssistDataModel\Models\Student; +use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Database\Eloquent\Relations\Relation; + +/** + * @extends Factory + */ +class ApplicationAuthenticationFactory extends Factory +{ + public function definition(): array + { + return [ + 'author_type' => fake()->randomElement([ + (new Student())->getMorphClass(), + (new Prospect())->getMorphClass(), + ]), + 'author_id' => function (array $attributes) { + $senderClass = Relation::getMorphedModel($attributes['author_type']); + + /** @var Student|Prospect $senderModel */ + $senderModel = new $senderClass(); + + $sender = $senderClass === Student::class + ? Student::inRandomOrder()->first() ?? Student::factory()->create() + : $senderModel::factory()->create(); + + return $sender->getKey(); + }, + 'code' => Hash::make(random_int(100000, 999999)), + 'application_id' => Application::factory(), + ]; + } +} diff --git a/app-modules/application/routes/api.php b/app-modules/application/routes/api.php index da03126487..ab4ff89898 100644 --- a/app-modules/application/routes/api.php +++ b/app-modules/application/routes/api.php @@ -36,9 +36,14 @@ use Assist\Application\Http\Controllers\ApplicationWidgetController; use Assist\Form\Http\Middleware\EnsureSubmissibleIsEmbeddableAndAuthorized; +use Assist\Application\Http\Middleware\EnsureOnlineAdmissionsFeatureIsActive; Route::prefix('api') - ->middleware(['api', EnsureSubmissibleIsEmbeddableAndAuthorized::class . ':application']) + ->middleware([ + 'api', + EnsureOnlineAdmissionsFeatureIsActive::class, + EnsureSubmissibleIsEmbeddableAndAuthorized::class . ':application', + ]) ->group(function () { Route::prefix('applications') ->name('applications.') diff --git a/app-modules/application/src/Http/Middleware/EnsureOnlineAdmissionsFeatureIsActive.php b/app-modules/application/src/Http/Middleware/EnsureOnlineAdmissionsFeatureIsActive.php new file mode 100644 index 0000000000..961b6c8a9e --- /dev/null +++ b/app-modules/application/src/Http/Middleware/EnsureOnlineAdmissionsFeatureIsActive.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. + + +*/ + +namespace Assist\Application\Http\Middleware; + +use Closure; +use Illuminate\Http\Request; +use App\Settings\LicenseSettings; +use Symfony\Component\HttpFoundation\Response; + +class EnsureOnlineAdmissionsFeatureIsActive +{ + public function handle(Request $request, Closure $next): Response + { + if (! app(LicenseSettings::class)->data->addons->onlineAdmissions) { + return response()->json(['error' => 'Online Admissions is not enabled.'], 403); + } + + return $next($request); + } +} diff --git a/app-modules/application/src/Policies/ApplicationPolicy.php b/app-modules/application/src/Policies/ApplicationPolicy.php index ddfad3d323..04e69131ac 100644 --- a/app-modules/application/src/Policies/ApplicationPolicy.php +++ b/app-modules/application/src/Policies/ApplicationPolicy.php @@ -37,11 +37,16 @@ namespace Assist\Application\Policies; use App\Models\User; +use App\Enums\Feature; use Illuminate\Auth\Access\Response; use Assist\Application\Models\Application; +use App\Concerns\FeatureAccessEnforcedPolicyBefore; +use App\Policies\Contracts\FeatureAccessEnforcedPolicy; -class ApplicationPolicy +class ApplicationPolicy implements FeatureAccessEnforcedPolicy { + use FeatureAccessEnforcedPolicyBefore; + public function viewAny(User $user): Response { return $user->canOrElse( @@ -97,4 +102,9 @@ public function forceDelete(User $user, Application $application): Response denyResponse: 'You do not have permission to permanently delete this application.' ); } + + protected function requiredFeatures(): array + { + return [Feature::OnlineAdmissions]; + } } diff --git a/app-modules/application/tests/.gitkeep b/app-modules/application/tests/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/app-modules/application/tests/Application/CreateApplicationTest.php b/app-modules/application/tests/Application/CreateApplicationTest.php new file mode 100644 index 0000000000..278e5a9bfb --- /dev/null +++ b/app-modules/application/tests/Application/CreateApplicationTest.php @@ -0,0 +1,104 @@ + + + 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 App\Models\User; +use App\Settings\LicenseSettings; + +use function Pest\Laravel\actingAs; +use function Pest\Livewire\livewire; + +use Assist\Application\Filament\Resources\ApplicationResource; + +// TODO: Write CreateApplication tests +//test('A successful action on the CreateApplication page', function () {}); +// +//test('CreateApplication requires valid data', function ($data, $errors) {})->with([]); + +// Permission Tests + +test('CreateApplication is gated with proper access control', function () { + $user = User::factory()->create(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('create') + )->assertForbidden(); + + livewire(ApplicationResource\Pages\CreateApplication::class) + ->assertForbidden(); + + $user->givePermissionTo('application.view-any'); + $user->givePermissionTo('application.create'); + + actingAs($user) + ->get( + ApplicationResource::getUrl('create') + )->assertSuccessful(); + + // TODO: Finish the test by adding the request factory CreateApplicationRequestFactory +}); + +test('CreateApplication is gated with proper feature access control', function () { + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $user = User::factory()->create(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('create') + )->assertForbidden(); + + $user->givePermissionTo('application.view-any'); + $user->givePermissionTo('application.create'); + + livewire(ApplicationResource\Pages\CreateApplication::class) + ->assertForbidden(); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('create') + )->assertSuccessful(); + + // TODO: Finish the test by adding the request factory CreateApplicationRequestFactory +}); diff --git a/app-modules/application/tests/Application/EditApplicationTest.php b/app-modules/application/tests/Application/EditApplicationTest.php new file mode 100644 index 0000000000..f901cad0f6 --- /dev/null +++ b/app-modules/application/tests/Application/EditApplicationTest.php @@ -0,0 +1,121 @@ + + + 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 App\Models\User; +use App\Settings\LicenseSettings; + +use function Pest\Laravel\actingAs; +use function Pest\Livewire\livewire; + +use Assist\Application\Models\Application; +use Assist\Application\Filament\Resources\ApplicationResource; + +// TODO: Write EditApplication tests +//test('A successful action on the EditApplication page', function () {}); +// +//test('EditApplication requires valid data', function ($data, $errors) {})->with([]); + +// Permission Tests + +test('EditApplication is gated with proper access control', function () { + $user = User::factory()->create(); + + $application = Application::factory()->create(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('edit', [ + 'record' => $application, + ]) + )->assertForbidden(); + + livewire(ApplicationResource\Pages\EditApplication::class, [ + 'record' => $application->getRouteKey(), + ]) + ->assertForbidden(); + + $user->givePermissionTo('application.view-any'); + $user->givePermissionTo('application.*.update'); + + actingAs($user) + ->get( + ApplicationResource::getUrl('edit', [ + 'record' => $application, + ]) + )->assertSuccessful(); + + // TODO: Finish the test by adding the request factory EditApplicationRequestFactory +}); + +test('EditApplication is gated with proper feature access control', function () { + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $user = User::factory()->create(); + + $user->givePermissionTo('application.view-any'); + $user->givePermissionTo('application.*.update'); + + $application = Application::factory()->create(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('edit', [ + 'record' => $application, + ]) + )->assertForbidden(); + + livewire(ApplicationResource\Pages\EditApplication::class, [ + 'record' => $application->getRouteKey(), + ]) + ->assertForbidden(); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('edit', [ + 'record' => $application, + ]) + )->assertSuccessful(); + + // TODO: Finish the test by adding the request factory EditApplicationRequestFactory +}); diff --git a/app-modules/application/tests/Application/ListApplicationsTest.php b/app-modules/application/tests/Application/ListApplicationsTest.php new file mode 100644 index 0000000000..f3f44e6adc --- /dev/null +++ b/app-modules/application/tests/Application/ListApplicationsTest.php @@ -0,0 +1,91 @@ + + + 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 App\Models\User; +use App\Settings\LicenseSettings; + +use function Pest\Laravel\actingAs; + +use Assist\Application\Filament\Resources\ApplicationResource; + +// TODO: Write ListApplications tests +//test('The correct details are displayed on the ListApplications page', function () {}); + +// TODO: Sorting and Searching tests + +// Permission Tests + +test('ListApplications is gated with proper access control', function () { + $user = User::factory()->create(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('index') + )->assertForbidden(); + + $user->givePermissionTo('application.view-any'); + + actingAs($user) + ->get( + ApplicationResource::getUrl('index') + )->assertSuccessful(); +}); + +test('ListApplications is gated with proper feature access control', function () { + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $user = User::factory()->create(); + + $user->givePermissionTo('application.view-any'); + + actingAs($user) + ->get( + ApplicationResource::getUrl('index') + )->assertForbidden(); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + actingAs($user) + ->get( + ApplicationResource::getUrl('index') + )->assertSuccessful(); +}); diff --git a/app-modules/application/tests/ApplicationWidgetApiTest.php b/app-modules/application/tests/ApplicationWidgetApiTest.php new file mode 100644 index 0000000000..9cdf6ae1e8 --- /dev/null +++ b/app-modules/application/tests/ApplicationWidgetApiTest.php @@ -0,0 +1,167 @@ + + + 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 function Pest\Laravel\get; +use function Pest\Laravel\post; + +use App\Settings\LicenseSettings; +use Illuminate\Support\Facades\URL; +use Assist\Prospect\Models\Prospect; +use Assist\Application\Models\Application; + +use function Pest\Laravel\withoutMiddleware; + +use Assist\Application\Models\ApplicationAuthentication; +use Assist\Form\Http\Middleware\EnsureSubmissibleIsEmbeddableAndAuthorized; + +test('define is protected with proper feature access control', function () { + withoutMiddleware([EnsureSubmissibleIsEmbeddableAndAuthorized::class]); + + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $application = Application::factory()->create(); + + get(URL::signedRoute('applications.define', ['application' => $application])) + ->assertForbidden() + ->assertJson([ + 'error' => 'Online Admissions is not enabled.', + ]); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + get(URL::signedRoute('applications.define', ['application' => $application])) + ->assertSuccessful(); +}); + +test('request-authentication is protected with proper feature access control', function () { + withoutMiddleware([EnsureSubmissibleIsEmbeddableAndAuthorized::class]); + + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $application = Application::factory()->create(); + + $prospect = Prospect::factory()->create(); + + post(URL::signedRoute('applications.request-authentication', ['application' => $application, 'email' => $prospect->email])) + ->assertForbidden() + ->assertJson([ + 'error' => 'Online Admissions is not enabled.', + ]); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + post(URL::signedRoute('applications.request-authentication', ['application' => $application, 'email' => $prospect->email])) + ->assertSuccessful(); +}); + +test('authenticate is protected with proper feature access control', function () { + withoutMiddleware([EnsureSubmissibleIsEmbeddableAndAuthorized::class]); + + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $application = Application::factory()->create(); + + $code = random_int(100000, 999999); + + $authorization = ApplicationAuthentication::factory()->create([ + 'application_id' => $application->id, + 'code' => Hash::make($code), + ]); + + post(URL::signedRoute('applications.authenticate', ['application' => $application, 'authentication' => $authorization, 'code' => $code])) + ->assertForbidden() + ->assertJson([ + 'error' => 'Online Admissions is not enabled.', + ]); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + post(URL::signedRoute('applications.authenticate', ['application' => $application, 'authentication' => $authorization, 'code' => $code])) + ->assertSuccessful(); +}); + +test('submit is protected with proper feature access control', function () { + withoutMiddleware([EnsureSubmissibleIsEmbeddableAndAuthorized::class]); + + $settings = app(LicenseSettings::class); + + $settings->data->addons->onlineAdmissions = false; + + $settings->save(); + + $application = Application::factory()->create(); + + $application->content = []; + + $application->save(); + + $application->fields()->delete(); + + $authorization = ApplicationAuthentication::factory()->create([ + 'application_id' => $application->id, + ]); + + post(URL::signedRoute('applications.submit', ['application' => $application, 'authentication' => $authorization])) + ->assertForbidden() + ->assertJson([ + 'error' => 'Online Admissions is not enabled.', + ]); + + $settings->data->addons->onlineAdmissions = true; + + $settings->save(); + + post(URL::signedRoute('applications.submit', ['application' => $application, 'authentication' => $authorization])) + ->assertSuccessful(); +}); diff --git a/app-modules/knowledge-base/tests/KnowledgeBaseItem/CreateKnowledgeBaseCategoryTest.php b/app-modules/knowledge-base/tests/KnowledgeBaseItem/CreateKnowledgeBaseItemTest.php similarity index 100% rename from app-modules/knowledge-base/tests/KnowledgeBaseItem/CreateKnowledgeBaseCategoryTest.php rename to app-modules/knowledge-base/tests/KnowledgeBaseItem/CreateKnowledgeBaseItemTest.php