Skip to content

Commit 74c6578

Browse files
Allow to view events, event series and organizations they are responsible for and to view, create and update documents
1 parent 33cfbb4 commit 74c6578

File tree

6 files changed

+92
-28
lines changed

6 files changed

+92
-28
lines changed

app/Models/Traits/HasResponsibleUsers.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ abstract public function getAbilityToViewResponsibilities(): Ability;
3535
public function getResponsibleUsersVisibleForCurrentUser(): Collection
3636
{
3737
$currentUser = Auth::user();
38-
39-
if (isset($currentUser) && $currentUser->hasAbility($this->getAbilityToViewResponsibilities())) {
38+
if (
39+
isset($currentUser) && (
40+
$currentUser->hasAbility($this->getAbilityToViewResponsibilities())
41+
|| $currentUser->isResponsibleFor($this)
42+
)
43+
) {
4044
return $this->responsibleUsers;
4145
}
4246

app/Models/User.php

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Illuminate\Database\Eloquent\Casts\Attribute;
1717
use Illuminate\Database\Eloquent\Collection;
1818
use Illuminate\Database\Eloquent\Factories\HasFactory;
19+
use Illuminate\Database\Eloquent\Model;
1920
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
2021
use Illuminate\Database\Eloquent\Relations\HasMany;
2122
use Illuminate\Database\Eloquent\Relations\MorphToMany;
@@ -226,6 +227,13 @@ public function hasAbility(Ability $ability): bool
226227
return false;
227228
}
228229

230+
public function isResponsibleFor(Model $model): bool
231+
{
232+
return ($model->responsibleUsers ?? Collection::empty())
233+
->pluck('id')
234+
->contains($this->id);
235+
}
236+
229237
public function loadProfileData(): self
230238
{
231239
$this->load([

app/Policies/DocumentPolicy.php

+48-18
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,34 @@ public function viewAny(User $user, Event|EventSeries|Organization|null $referen
2828
return $this->deny();
2929
}
3030

31-
return match ($reference::class) {
32-
Event::class => $this->requireAbility($user, Ability::ViewDocumentsOfEvents),
33-
EventSeries::class => $this->requireAbility($user, Ability::ViewDocumentsOfEventSeries),
34-
Organization::class => $this->requireAbility($user, Ability::ViewDocumentsOfOrganizations),
35-
default => $this->deny(),
36-
};
31+
if ($user->hasAbility(Ability::ViewDocuments)) {
32+
// ViewDocuments grants access to all documents.
33+
return $this->allow();
34+
}
35+
36+
return $this->requireAbilityOrResponsibleUser(
37+
match ($reference::class) {
38+
Event::class => $this->requireAbility($user, Ability::ViewDocumentsOfEvents),
39+
EventSeries::class => $this->requireAbility($user, Ability::ViewDocumentsOfEventSeries),
40+
Organization::class => $this->requireAbility($user, Ability::ViewDocumentsOfOrganizations),
41+
default => $this->deny(),
42+
},
43+
$user,
44+
$reference
45+
);
46+
}
47+
48+
private function requireAbilityOrResponsibleUser(
49+
Response $abilityResponse,
50+
User $user,
51+
Event|EventSeries|Organization $reference
52+
): Response {
53+
if ($abilityResponse->allowed()) {
54+
return $abilityResponse;
55+
}
56+
57+
// Responsible users can always access documents of their events, event series and organizations.
58+
return $this->response($user->isResponsibleFor($reference));
3759
}
3860

3961
/**
@@ -58,12 +80,16 @@ public function create(User $user, Event|EventSeries|Organization $reference): R
5880
return $this->deny();
5981
}
6082

61-
return match ($reference::class) {
62-
Event::class => $this->requireAbility($user, Ability::AddDocumentsToEvents),
63-
EventSeries::class => $this->requireAbility($user, Ability::AddDocumentsToEventSeries),
64-
Organization::class => $this->requireAbility($user, Ability::AddDocumentsToOrganizations),
65-
default => $this->deny(),
66-
};
83+
return $this->requireAbilityOrResponsibleUser(
84+
match ($reference::class) {
85+
Event::class => $this->requireAbility($user, Ability::AddDocumentsToEvents),
86+
EventSeries::class => $this->requireAbility($user, Ability::AddDocumentsToEventSeries),
87+
Organization::class => $this->requireAbility($user, Ability::AddDocumentsToOrganizations),
88+
default => $this->deny(),
89+
},
90+
$user,
91+
$reference
92+
);
6793
}
6894

6995
/**
@@ -75,12 +101,16 @@ public function update(User $user, Document $document): Response
75101
return $this->deny();
76102
}
77103

78-
return match ($document->reference::class) {
79-
Event::class => $this->requireAbility($user, Ability::EditDocumentsOfEvents),
80-
EventSeries::class => $this->requireAbility($user, Ability::EditDocumentsOfEventSeries),
81-
Organization::class => $this->requireAbility($user, Ability::EditDocumentsOfOrganizations),
82-
default => $this->deny(),
83-
};
104+
return $this->requireAbilityOrResponsibleUser(
105+
match ($document->reference::class) {
106+
Event::class => $this->requireAbility($user, Ability::EditDocumentsOfEvents),
107+
EventSeries::class => $this->requireAbility($user, Ability::EditDocumentsOfEventSeries),
108+
Organization::class => $this->requireAbility($user, Ability::EditDocumentsOfOrganizations),
109+
default => $this->deny(),
110+
},
111+
$user,
112+
$document->reference
113+
);
84114
}
85115

86116
/**

app/Policies/EventPolicy.php

+14-3
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,16 @@ public function view(?User $user, Event $event): Response
3131
return $this->allow();
3232
}
3333

34-
// Private events are only visible for logged-in users with the ability to view private events as well.
35-
return $this->requireAbility($user, Ability::ViewPrivateEvents);
34+
/**
35+
* Private events are only visible for
36+
* - logged-in users with the ability to view private events as well
37+
* - and the responsible users.
38+
*/
39+
return $this->requireAbilityOrCheck(
40+
$user,
41+
Ability::ViewPrivateEvents,
42+
fn () => $this->response(isset($user) && $user->isResponsibleFor($event))
43+
);
3644
}
3745

3846
public function viewGroups(User $user, Event $event): Response
@@ -54,7 +62,10 @@ public function viewResponsibilities(?User $user, Event $event): Response
5462
return $this->requireAbilityOrCheck(
5563
$user,
5664
Ability::ViewResponsibilitiesOfEvents,
57-
fn () => $this->response($event->hasPubliclyVisibleResponsibleUsers())
65+
fn () => $this->response(
66+
$event->hasPubliclyVisibleResponsibleUsers()
67+
|| (isset($user) && $user->isResponsibleFor($event))
68+
)
5869
);
5970
}
6071

app/Policies/EventSeriesPolicy.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@ public function view(?User $user, EventSeries $eventSeries): Response
3232
}
3333

3434
/**
35-
* Private event series are only visible for logged-in users
36-
* with the ability to view private event series as well.
35+
* Private event series are only visible for
36+
* - logged-in users with the ability to view private event series as well
37+
* - and the responsible users.
3738
*/
38-
return $this->requireAbility($user, Ability::ViewPrivateEventSeries);
39+
return $this->requireAbilityOrCheck(
40+
$user,
41+
Ability::ViewPrivateEventSeries,
42+
fn () => $this->response(isset($user) && $user->isResponsibleFor($eventSeries))
43+
);
3944
}
4045

4146
public function viewResponsibilities(?User $user, EventSeries $eventSeries): Response
@@ -48,7 +53,10 @@ public function viewResponsibilities(?User $user, EventSeries $eventSeries): Res
4853
return $this->requireAbilityOrCheck(
4954
$user,
5055
Ability::ViewResponsibilitiesOfEventSeries,
51-
fn () => $this->response($eventSeries->hasPubliclyVisibleResponsibleUsers())
56+
fn () => $this->response(
57+
$eventSeries->hasPubliclyVisibleResponsibleUsers()
58+
|| (isset($user) && $user->isResponsibleFor($eventSeries))
59+
)
5260
);
5361
}
5462

app/Policies/OrganizationPolicy.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ public function viewResponsibilities(?User $user, Organization $organization): R
3838
return $this->requireAbilityOrCheck(
3939
$user,
4040
Ability::ViewResponsibilitiesOfOrganizations,
41-
fn () => $this->response($organization->hasPubliclyVisibleResponsibleUsers())
41+
fn () => $this->response(
42+
$organization->hasPubliclyVisibleResponsibleUsers()
43+
|| (isset($user) && $user->isResponsibleFor($organization))
44+
)
4245
);
4346
}
4447

0 commit comments

Comments
 (0)