Skip to content

Commit a9d7aab

Browse files
committed
Filter away person-related data in public camps
1 parent 3f3b7d4 commit a9d7aab

22 files changed

+150
-30
lines changed

api/migrations/schema/Version20250821113132.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,45 @@ public function getDescription(): string {
1515
public function up(Schema $schema): void {
1616
$this->addSql('ALTER TABLE camp ADD isShared BOOLEAN DEFAULT FALSE NOT NULL');
1717
$this->addSql('CREATE INDEX IDX_C1944230D2E4FE61 ON camp (isShared)');
18+
$this->addSql(
19+
<<<'EOF'
20+
CREATE OR REPLACE VIEW public.view_user_camps
21+
AS
22+
select cc.id::TEXT, cc.userid, cc.campid
23+
from camp_collaboration cc
24+
where cc.status = 'established'
25+
EOF
26+
);
27+
$this->addSql(
28+
<<<'EOF'
29+
CREATE OR REPLACE VIEW public.view_user_camps_with_public
30+
AS
31+
SELECT CONCAT(u.id, c.id) id, u.id userid, c.id campid
32+
from camp c, "user" u
33+
where c.isprototype = TRUE or c.isshared = TRUE
34+
union all
35+
select cc.id, cc.userid, cc.campid
36+
from camp_collaboration cc
37+
where cc.status = 'established'
38+
EOF
39+
);
1840
}
1941

2042
public function down(Schema $schema): void {
43+
$this->addSql('DROP VIEW IF EXISTS public.view_user_camps_with_public');
44+
$this->addSql(
45+
<<<'EOF'
46+
CREATE OR REPLACE VIEW public.view_user_camps
47+
AS
48+
SELECT CONCAT(u.id, c.id) id, u.id userid, c.id campid
49+
from camp c, "user" u
50+
where c.isprototype = TRUE
51+
union all
52+
select cc.id, cc.userid, cc.campid
53+
from camp_collaboration cc
54+
where cc.status = 'established'
55+
EOF
56+
);
2157
$this->addSql('DROP INDEX IDX_C1944230D2E4FE61');
2258
$this->addSql('ALTER TABLE camp DROP isShared');
2359
}

api/src/Entity/Activity.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,17 @@ public function removeScheduleEntry(ScheduleEntry $scheduleEntry): self {
274274
/**
275275
* @return ActivityResponsible[]
276276
*/
277-
#[ApiProperty(readableLink: true)]
277+
#[ApiProperty(readableLink: true, security: '!is_granted("CAMP_COLLABORATOR", object)')]
278+
#[SerializedName('activityResponsibles')]
279+
#[Groups(['Activity:ActivityResponsibles'])]
280+
public function getRedactedEmbeddedActivityResponsibles(): array {
281+
return [];
282+
}
283+
284+
/**
285+
* @return ActivityResponsible[]
286+
*/
287+
#[ApiProperty(readableLink: true, security: 'is_granted("CAMP_COLLABORATOR", object)')]
278288
#[SerializedName('activityResponsibles')]
279289
#[Groups(['Activity:ActivityResponsibles'])]
280290
public function getEmbeddedActivityResponsibles(): array {

api/src/Entity/Camp.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,21 @@ class Camp extends BaseEntity implements BelongsToCampInterface, CopyFromPrototy
7979
public Collection $collaborations;
8080

8181
/**
82-
* UserCamp Collections
83-
* Based von view_user_camps; lists all user who can see this camp.
82+
* UserCamp Collection
83+
* Based von view_user_camps; lists all user who can see this camp through campCollaborations.
8484
*/
8585
#[ORM\OneToMany(targetEntity: UserCamp::class, mappedBy: 'camp')]
8686
public Collection $userCamps;
8787

88+
/**
89+
* UserCampWithPublic Collection
90+
* Based von view_user_camps_with_public; lists all user who can see this camp, through
91+
* campCollaborations or because the camps are prototypes or shared.
92+
*/
93+
#[ORM\OneToMany(targetEntity: UserCampWithPublic::class, mappedBy: 'camp')]
94+
#[Assert\DisableAutoMapping]
95+
public Collection $userCampsWithPublic;
96+
8897
/**
8998
* The time periods of the camp, there must be at least one. Periods in a camp may not overlap.
9099
* When creating a camp, the initial periods may be specified as nested payload, but updating,
@@ -462,13 +471,20 @@ public function getCampCollaborations(): array {
462471
return [];
463472
}
464473

474+
#[ApiProperty(writable: false, readableLink: true, security: '!is_granted("CAMP_COLLABORATOR", object)')]
475+
#[SerializedName('campCollaborations')]
476+
#[Groups('Camp:CampCollaborations')]
477+
public function getRedactedEmbeddedCampCollaborations(): array {
478+
return [];
479+
}
480+
465481
/**
466482
* The people working on planning and carrying out the camp. Only collaborators have access
467483
* to the camp's contents.
468484
*
469485
* @return CampCollaboration[]
470486
*/
471-
#[ApiProperty(writable: false, readableLink: true)]
487+
#[ApiProperty(writable: false, readableLink: true, security: 'is_granted("CAMP_COLLABORATOR", object)')]
472488
#[SerializedName('campCollaborations')]
473489
#[Groups('Camp:CampCollaborations')]
474490
public function getEmbeddedCampCollaborations(): array {

api/src/Entity/Day.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,26 @@ public function getEnd(): ?\DateTime {
180180
}
181181
}
182182

183-
/**
184-
* DayResponsible.
185-
*/
183+
#[ApiProperty(
184+
readableLink: true,
185+
uriTemplate: DayResponsible::DAY_SUBRESOURCE_URI_TEMPLATE,
186+
security: '!is_granted("CAMP_COLLABORATOR", object)'
187+
)]
188+
#[SerializedName('dayResponsibles')]
189+
#[Groups(['Day:DayResponsibles'])]
190+
public function getRedactedEmbeddedDayResponsibles(): array {
191+
return [];
192+
}
186193

187194
/**
195+
* People who have a special responsibility on this day.
196+
*
188197
* @return DayResponsible[]
189198
*/
190199
#[ApiProperty(
191200
readableLink: true,
192201
uriTemplate: DayResponsible::DAY_SUBRESOURCE_URI_TEMPLATE,
202+
security: 'is_granted("CAMP_COLLABORATOR", object)'
193203
)]
194204
#[SerializedName('dayResponsibles')]
195205
#[Groups(['Day:DayResponsibles'])]

api/src/Entity/DayResponsible.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@
4242
is_granted("CAMP_IS_SHARED", day) or
4343
is_granted("CAMP_IS_PROTOTYPE", day)'
4444
),
45-
],
46-
extraProperties: [
47-
'filter_by_current_user' => false,
4845
]
4946
),
5047
new Post(

api/src/Entity/User.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,20 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
8888
public Collection $collaborations;
8989

9090
/**
91-
* UserCamp Collections
92-
* Based von view_user_camps; lists all camps a user can see.
91+
* UserCamp Collection
92+
* Based von view_user_camps; lists all camps a user can see through their campCollaborations.
9393
*/
9494
#[ORM\OneToMany(targetEntity: UserCamp::class, mappedBy: 'user')]
9595
public Collection $userCamps;
9696

97+
/**
98+
* UserCampWithPublic Collection
99+
* Based von view_user_camps_with_public; lists all camps a user can see, through their
100+
* campCollaborations or because the camp is a prototype or shared.
101+
*/
102+
#[ORM\OneToMany(targetEntity: UserCampWithPublic::class, mappedBy: 'user')]
103+
public Collection $userCampsWithPublic;
104+
97105
/**
98106
* The state of this user.
99107
*/

api/src/Entity/UserCamp.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
/**
88
* view_user_camps
9-
* List all visible camps for each user.
9+
* List all visible camps for each user through their camp collaborations.
1010
*/
1111
#[ORM\Entity(readOnly: true)]
1212
#[ORM\Table(name: 'view_user_camps')]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace App\Entity;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
/**
8+
* view_user_camps_with_public
9+
* List all visible camps for each user, through camp collaborations or because
10+
* they are prototype or shared camps.
11+
*/
12+
#[ORM\Entity(readOnly: true)]
13+
#[ORM\Table(name: 'view_user_camps_with_public')]
14+
class UserCampWithPublic {
15+
#[ORM\Id]
16+
#[ORM\Column(type: 'string', length: 32, nullable: false)]
17+
public string $id;
18+
19+
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'userCampsWithPublic')]
20+
public User $user;
21+
22+
#[ORM\ManyToOne(targetEntity: Camp::class, inversedBy: 'userCampsWithPublic')]
23+
public Camp $camp;
24+
}

api/src/Repository/ActivityProgressLabelRepository.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ public function __construct(EntityManagerInterface $em, string $entityClass = Ac
3030

3131
public function filterByUser(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, User $user): void {
3232
$rootAlias = $queryBuilder->getRootAliases()[0];
33-
$this->filterByCampCollaboration($queryBuilder, $user, "{$rootAlias}.camp");
33+
$this->filterByCampCollaborationOrPublic($queryBuilder, $user, "{$rootAlias}.camp");
3434
}
3535
}

api/src/Repository/ActivityRepository.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ public function __construct(ManagerRegistry $registry) {
2424

2525
public function filterByUser(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, User $user): void {
2626
$rootAlias = $queryBuilder->getRootAliases()[0];
27-
$this->filterByCampCollaboration($queryBuilder, $user, "{$rootAlias}.camp");
27+
$this->filterByCampCollaborationOrPublic($queryBuilder, $user, "{$rootAlias}.camp");
2828
}
2929
}

0 commit comments

Comments
 (0)