Skip to content

Commit

Permalink
[AIDAPP-302]: Prevent users from being able to edit service requests …
Browse files Browse the repository at this point in the history
…of types if they are not managers (#279)

* Prevent users from viewing service requests of types that they are not managers or auditors of

* removed pysh file

* Prevent users from being able to edit service requests of types if they are not managers

* fix test cases

* Resolve suggestions

* Fix test case issue

* chore: fix enforcement of copyright on all files

* chore: fix code style

* Ensure the type is taken into account for the respondent check

Signed-off-by: Kevin Ullyott <kevin.ullyott@canyongbs.com>

* Fix bulk delete check

Signed-off-by: Kevin Ullyott <kevin.ullyott@canyongbs.com>

* Fix the policy

Signed-off-by: Kevin Ullyott <kevin.ullyott@canyongbs.com>

---------

Signed-off-by: Kevin Ullyott <kevin.ullyott@canyongbs.com>
Co-authored-by: ankit-canyon <ankit-canyon@users.noreply.github.com>
Co-authored-by: joelicatajr <joelicatajr@users.noreply.github.com>
Co-authored-by: Kevin Ullyott <kevin.ullyott@canyongbs.com>
  • Loading branch information
4 people authored Oct 16, 2024
1 parent 07a6f28 commit a4da371
Show file tree
Hide file tree
Showing 10 changed files with 529 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ public function table(Table $table): Table
{
return $table
->recordTitleAttribute('id')
->modifyQueryUsing(function ($query) {
$query->when(! auth()->user()->hasRole('authorization.super_admin'), function (Builder $q) {
return $q->whereHas('priority.type.managers', function (Builder $query): void {
$query->where('teams.id', auth()->user()->teams()->first()?->getKey());
})
->orWhereHas('priority.type.auditors', function (Builder $query): void {
$query->where('teams.id', auth()->user()->teams()->first()?->getKey());
})
->whereHas('respondent', function (Builder $query) {
$query
->where('respondent_id', $this->getOwnerRecord()->getKey())
->where('respondent_type', $this->getOwnerRecord()->getMorphClass());
});
});
})
->columns([
IdColumn::make(),
TextColumn::make('service_request_number')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
use AidingApp\ServiceManagement\Models\ServiceRequestType;
use AidingApp\ServiceManagement\Models\ServiceRequestStatus;
use AidingApp\ServiceManagement\Models\ServiceRequestPriority;
use AidingApp\ServiceManagement\Rules\ManagedServiceRequestType;
use AidingApp\ServiceManagement\Filament\Resources\ServiceRequestResource;

class CreateServiceRequest extends CreateRecord
Expand Down Expand Up @@ -83,7 +84,13 @@ public function form(Form $form): Form
Grid::make()
->schema([
Select::make('type_id')
->options(ServiceRequestType::pluck('name', 'id'))
->options(ServiceRequestType::when(! auth()->user()->hasRole('authorization.super_admin'), function (Builder $query) {
$query->whereHas('managers', function (Builder $query): void {
$query->where('teams.id', auth()->user()->teams()->first()?->getKey());
});
})
->pluck('name', 'id'))
->rule(new ManagedServiceRequestType())
->afterStateUpdated(fn (Set $set) => $set('priority_id', null))
->label('Type')
->required()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
use AidingApp\ServiceManagement\Models\ServiceRequestStatus;
use AidingApp\ServiceManagement\Models\ServiceRequestPriority;
use AidingApp\ServiceManagement\Rules\ManagedServiceRequestType;
use AidingApp\ServiceManagement\Filament\Resources\ServiceRequestResource;
use AidingApp\ServiceManagement\Actions\ResolveUploadsMediaCollectionForServiceRequest;

Expand Down Expand Up @@ -99,12 +100,18 @@ public function form(Form $form): Form
fn (ServiceRequest $record) => ServiceRequestType::withTrashed()
->whereKey($record->priority?->type_id)
->orWhereNull('deleted_at')
->when(! auth()->user()->hasRole('authorization.super_admin'), function (Builder $query) {
$query->whereHas('managers', function (Builder $query): void {
$query->where('teams.id', auth()->user()->teams()->first()?->getKey());
});
})
->orderBy('name')
->pluck('name', 'id')
)
->afterStateUpdated(fn (Set $set) => $set('priority_id', null))
->label('Type')
->required()
->rule(new ManagedServiceRequestType())
->live()
->exists(ServiceRequestType::class, 'id')
->disableOptionWhen(fn (string $value) => $disabledTypes->contains($value)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Notifications\Notification;
use App\Filament\Tables\Columns\IdColumn;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Filters\SelectFilter;
Expand Down Expand Up @@ -146,7 +147,24 @@ public function table(Table $table): Table
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->action(function ($records) {
$deletedRecordsCount = ServiceRequest::query()
->whereKey($records)
->when(! auth()->user()->hasRole('authorization.super_admin'), function (Builder $query) {
$query->whereHas('priority.type.managers', function (Builder $query): void {
$query->where('teams.id', auth()->user()->teams()->first()?->getKey());
});
})
->delete();

Notification::make()
->title('Deleted ' . $deletedRecordsCount . ' prompt types')
->body(($deletedRecordsCount < $records->count()) ? ($records->count() - $deletedRecordsCount) . ' service requests were not deleted because you\'re not an auditor or manager of it.' : null)
->success()
->send();
})
->fetchSelectedRecords(false),
]),
])
->defaultSort('created_at', 'desc')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,7 @@ public function view(Authenticatable $authenticatable, ServiceRequest $serviceRe
if (! auth()->user()->hasRole('authorization.super_admin')) {
$team = auth()->user()->teams()->first();

if (! $serviceRequest?->priority?->type?->managers()->exists() && ! $serviceRequest?->priority?->type?->auditors()->exists()) {
return Response::deny("You don't have permission to view this service request because you're not an auditor or manager.");
}

if (! $serviceRequest?->priority?->type?->managers->contains('id', $team?->getKey()) && ! $serviceRequest?->priority?->type?->auditors->contains('id', $team?->getKey())) {
if (! $serviceRequest?->priority?->type?->managers?->contains('id', $team?->getKey()) && ! $serviceRequest?->priority?->type?->auditors?->contains('id', $team?->getKey())) {
return Response::deny("You don't have permission to view this service request because you're not an auditor or manager.");
}
}
Expand All @@ -96,6 +92,14 @@ public function view(Authenticatable $authenticatable, ServiceRequest $serviceRe

public function create(Authenticatable $authenticatable): Response
{
if (! auth()->user()->hasRole('authorization.super_admin')) {
$team = auth()->user()->teams()->first();

if (! $team?->managableServiceRequestTypes()->exists()) {
return Response::deny("You don't have permission to create service requests because you're not a manager of any service request types.");
}
}

return $authenticatable->canOrElse(
abilities: 'service_request.create',
denyResponse: 'You do not have permission to create service requests.'
Expand All @@ -112,6 +116,14 @@ public function update(Authenticatable $authenticatable, ServiceRequest $service
return Response::deny('Closed service request cannot be edited.');
}

if (! auth()->user()->hasRole('authorization.super_admin')) {
$team = auth()->user()->teams()->first();

if (! $serviceRequest?->priority?->type?->managers?->contains('id', $team?->getKey())) {
return Response::deny("You don't have permission to update this service request because you're not a manager of it's type.");
}
}

return $authenticatable->canOrElse(
abilities: ['service_request.*.update', "service_request.{$serviceRequest->id}.update"],
denyResponse: 'You do not have permission to update this service request.'
Expand All @@ -124,6 +136,14 @@ public function delete(Authenticatable $authenticatable, ServiceRequest $service
return Response::deny('You do not have permission to delete this service request.');
}

if (! auth()->user()->hasRole('authorization.super_admin')) {
$team = auth()->user()->teams()->first();

if (! $serviceRequest?->priority?->type?->managers?->contains('id', $team?->getKey())) {
return Response::deny("You don't have permission to delete this service request because you're not a manager of it's type.");
}
}

return $authenticatable->canOrElse(
abilities: ['service_request.*.delete', "service_request.{$serviceRequest->id}.delete"],
denyResponse: 'You do not have permission to delete this service request.'
Expand All @@ -136,6 +156,14 @@ public function restore(Authenticatable $authenticatable, ServiceRequest $servic
return Response::deny('You do not have permission to restore this service request.');
}

if (! auth()->user()->hasRole('authorization.super_admin')) {
$team = auth()->user()->teams()->first();

if (! $serviceRequest?->priority?->type?->managers?->contains('id', $team?->getKey())) {
return Response::deny("You don't have permission to restore this service request because you're not a manager of it's type.");
}
}

return $authenticatable->canOrElse(
abilities: ['service_request.*.restore', "service_request.{$serviceRequest->id}.restore"],
denyResponse: 'You do not have permission to restore this service request.'
Expand All @@ -148,6 +176,14 @@ public function forceDelete(Authenticatable $authenticatable, ServiceRequest $se
return Response::deny('You do not have permission to permanently delete this service request.');
}

if (! auth()->user()->hasRole('authorization.super_admin')) {
$team = auth()->user()->teams()->first();

if (! $serviceRequest?->priority?->type?->managers?->contains('id', $team?->getKey())) {
return Response::deny("You don't have permission to permanently delete this service request because you're not a manager of it's type.");
}
}

return $authenticatable->canOrElse(
abilities: ['service_request.*.force-delete', "service_request.{$serviceRequest->id}.force-delete"],
denyResponse: 'You do not have permission to permanently delete this service request.'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
<COPYRIGHT>
Copyright © 2016-2024, Canyon GBS LLC. All rights reserved.
Aiding App™ is licensed under the Elastic License 2.0. For more details,
see <https://github.com/canyongbs/aidingapp/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 Aiding 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.
</COPYRIGHT>
*/

namespace AidingApp\ServiceManagement\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Translation\PotentiallyTranslatedString;
use AidingApp\ServiceManagement\Models\ServiceRequestType;

class ManagedServiceRequestType implements ValidationRule
{
/**
* Run the validation rule.
*
* @param PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (auth()->user()->hasRole('authorization.super_admin')) {
return;
}

$team = auth()->user()->teams()->first();

$isManager = ServiceRequestType::where('id', $value)
->whereHas('managers', function ($query) use ($team) {
$query->where('teams.id', $team?->getKey());
})
->exists();

if (! $isManager) {
$fail('You are not authorized to select this service request type.');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ class CreateServiceRequestRequestFactory extends RequestFactory
{
public function definition(): array
{
$priority = ServiceRequestPriority::factory()->create();

return [
'title' => fake()->words(2, true),
'division_id' => Division::inRandomOrder()->first()?->id ?? Division::factory()->create()->id,
'status_id' => ServiceRequestStatus::factory()->create()->id,
'type_id' => $priority->type_id,
'priority_id' => $priority->id,
'type_id' => function (array $attributes) {
return ServiceRequestPriority::find($attributes['priority_id'])->type->getKey();
},
'priority_id' => ServiceRequestPriority::factory()->create()->getKey(),
'respondent_id' => Contact::factory()->create()->getKey(),
'respondent_type' => app(Contact::class)->getMorphClass(),
'close_details' => fake()->sentence(),
Expand Down
Loading

0 comments on commit a4da371

Please sign in to comment.