Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change permission to see reference projector #1015

Merged
merged 9 commits into from
Sep 23, 2024
7 changes: 6 additions & 1 deletion internal/restrict/collection/mediafile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,12 @@ func TestMediafileModeA(t *testing.T) {
meeting_mediafile/2:
meeting_id: 7
projection_ids: [4]
projection/4/current_projector_id: 5

projection/4:
current_projector_id: 5
meeting_id: 7

projector/5/meeting_id: 7

meeting/7:
committee_id: 404
Expand Down
28 changes: 13 additions & 15 deletions internal/restrict/collection/meeting_mediafile.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
//
// The user is an admin of the meeting.
// The user can see the meeting and used_as_logo_*_in_meeting_id or used_as_font_*_in_meeting_id is not empty.
// The user has projector.can_see and one of the projections linked with meeting_mediafile/projection_ids has projection/current_projector_id set.
// The user can see a projection linked in `meeting_mediafile/projection_ids`.
// The user has mediafile.can_see and either:
// meeting_mediafile/is_public is true, or
// the user has groups in common with meeting_mediafile/inherited_access_group_ids.
Expand Down Expand Up @@ -47,6 +47,8 @@ func (m MeetingMediafile) Modes(mode string) FieldRestricter {
}

func (m MeetingMediafile) see(ctx context.Context, ds *dsfetch.Fetch, meetingMediafileIDs ...int) ([]int, error) {
projectionRestrictor := Collection(ctx, "projection").Modes("A")

return eachMeeting(ctx, ds, m, meetingMediafileIDs, func(meetingID int, ids []int) ([]int, error) {
canSeeMeeting, err := Collection(ctx, Meeting{}.Name()).Modes("B")(ctx, ds, meetingID)
if err != nil {
Expand Down Expand Up @@ -76,22 +78,18 @@ func (m MeetingMediafile) see(ctx context.Context, ds *dsfetch.Fetch, meetingMed
return true, nil
}

if perms.Has(perm.ProjectorCanSee) {
p7onIDs, err := ds.MeetingMediafile_ProjectionIDs(meetingMediafileID).Value(ctx)
if err != nil {
return false, fmt.Errorf("getting projection ids: %w", err)
}
p7onIDs, err := ds.MeetingMediafile_ProjectionIDs(meetingMediafileID).Value(ctx)
if err != nil {
return false, fmt.Errorf("getting projection ids: %w", err)
}

for _, p7onID := range p7onIDs {
value, err := ds.Projection_CurrentProjectorID(p7onID).Value(ctx)
if err != nil {
return false, fmt.Errorf("getting current projector id: %w", err)
}
allowedP7ons, err := projectionRestrictor(ctx, ds, p7onIDs...)
if err != nil {
return false, fmt.Errorf("checking p7on restriction: %w", err)
}

if !value.Null() {
return true, nil
}
}
if len(allowedP7ons) > 0 {
return true, nil
}

if perms.Has(perm.MediafileCanSee) {
Expand Down
37 changes: 35 additions & 2 deletions internal/restrict/collection/meeting_mediafile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,12 @@ func TestMeetingMediafileModeA(t *testing.T) {
meeting_mediafile/1:
meeting_id: 7
projection_ids: [4]
projection/4/current_projector_id: 5

projection/4:
current_projector_id: 5
meeting_id: 7

projector/5/meeting_id: 7

meeting/7:
committee_id: 404
Expand Down Expand Up @@ -161,11 +166,39 @@ func TestMeetingMediafileModeA(t *testing.T) {
group/2/meeting_user_ids: [10]
meeting_user/10/user_id: 1

projection/4/id: 4
projection/4/meeting_id: 7
`,
withPerms(7, perm.ProjectorCanSee),
)

testCase(
"On autopilot projector with meeting.can_see_autopilot",
t,
m.Modes("A"),
true,
`---
meeting_mediafile/1:
meeting_id: 30
projection_ids: [4]

projection/4:
current_projector_id: 7
meeting_id: 30

projector/7:
used_as_reference_projector_meeting_id: 30
meeting_id: 30

meeting/30:
committee_id: 404
group_ids: [2]

group/2/meeting_user_ids: [10]
meeting_user/10/user_id: 1
`,
withPerms(30, perm.MeetingCanSeeAutopilot),
)

testCase(
"meeting mediafile can_manage",
t,
Expand Down
50 changes: 48 additions & 2 deletions internal/restrict/collection/projection.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (

// Projection handels the restriction for the projection collection.
//
// The user can see a projection, if the user has projector.can_see.
// The user can see a projection,
// * if he has projector.can_manage or
// * he can see the projector linked in projection/current_projector_id.
//
// Mode A: The user can see the projection.
type Projection struct{}
Expand Down Expand Up @@ -40,5 +42,49 @@ func (p Projection) Modes(mode string) FieldRestricter {
}

func (p Projection) see(ctx context.Context, ds *dsfetch.Fetch, projectionIDs ...int) ([]int, error) {
return meetingPerm(ctx, ds, p, projectionIDs, perm.ProjectorCanSee)
projectorRestrictor := Collection(ctx, "projector").Modes("A")

return eachMeeting(ctx, ds, p, projectionIDs, func(meetingID int, ids []int) ([]int, error) {
perms, err := perm.FromContext(ctx, meetingID)
if err != nil {
return nil, fmt.Errorf("getting permission: %w", err)
}

if perms.Has(perm.ProjectorCanManage) {
return ids, nil
}

currentProjector := make([]dsfetch.Maybe[int], len(ids))
for i, id := range ids {
ds.Projection_CurrentProjectorID(id).Lazy(&currentProjector[i])
}

if err := ds.Execute(ctx); err != nil {
return nil, fmt.Errorf("reading current_projector_id")
}

var allowed []int
for i, maybeID := range currentProjector {
projectorID, hasCurrent := maybeID.Value()
if !hasCurrent {
continue
}

// This chekcs each projector by its own. But the result should be
// in the cache anyway. So this should be more performent, then
// putting many projector-ids in a set.
canSeeProjector, err := projectorRestrictor(ctx, ds, projectorID)
if err != nil {
return nil, fmt.Errorf("checking projector restrictor: %w", err)
}

if len(canSeeProjector) == 0 {
continue
}

allowed = append(allowed, ids[i])
}

return allowed, nil
})
}
52 changes: 50 additions & 2 deletions internal/restrict/collection/projection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ func TestProjectionModeA(t *testing.T) {
f := collection.Projection{}.Modes("A")

testCase(
"can see",
"manager",
t,
f,
true,
"projection/1/meeting_id: 30",
withPerms(30, perm.ProjectorCanSee),
withPerms(30, perm.ProjectorCanManage),
)

testCase(
Expand All @@ -26,4 +26,52 @@ func TestProjectionModeA(t *testing.T) {
false,
"projection/1/meeting_id: 30",
)

testCase(
"linked on reference projector with no perms",
t,
f,
false,
`
projection/1:
meeting_id: 30
current_projector_id: 7

projector/7:
used_as_reference_projector_meeting_id: 30
meeting_id: 30
`,
)

testCase(
"linked on reference projector with meeting.can_see_autopilote",
t,
f,
true,
`
projection/1:
meeting_id: 30
current_projector_id: 7

projector/7:
used_as_reference_projector_meeting_id: 30
meeting_id: 30
`,
withPerms(30, perm.MeetingCanSeeAutopilot),
)

testCase(
"linked on normal projector with projector.can_see",
t,
f,
true,
`
projection/1:
meeting_id: 30
current_projector_id: 7

projector/7/meeting_id: 30
`,
withPerms(30, perm.ProjectorCanSee),
)
}
20 changes: 14 additions & 6 deletions internal/restrict/collection/projector.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (

// Projector handels the restriction for the projector collection.
//
// The user can see a projector, if the user has projector.can_see.
// The user can see a projector,
// * if the user has projector.can_see or
// * the projector is the reference projector and the user has meeting.can_see_autopilot.
//
// If the projector has internal=true, then the user needs projector.can_manage
//
Expand Down Expand Up @@ -52,13 +54,11 @@ func (p Projector) see(ctx context.Context, ds *dsfetch.Fetch, projectorIDs ...i
return projectorIDs, nil
}

if !perms.Has(perm.ProjectorCanSee) {
return nil, nil
}

internalProjectorIDs := make([]bool, len(projectorIDs))
usedAsReference := make([]dsfetch.Maybe[int], len(projectorIDs))
for i, projectorID := range projectorIDs {
ds.Projector_IsInternal(projectorID).Lazy(&internalProjectorIDs[i])
ds.Projector_UsedAsReferenceProjectorMeetingID(projectorID).Lazy(&usedAsReference[i])
}

if err := ds.Execute(ctx); err != nil {
Expand All @@ -67,7 +67,15 @@ func (p Projector) see(ctx context.Context, ds *dsfetch.Fetch, projectorIDs ...i

var allowed []int
for i, projectorID := range projectorIDs {
if !internalProjectorIDs[i] {
if internalProjectorIDs[i] {
continue
}

if !usedAsReference[i].Null() && perms.Has(perm.MeetingCanSeeAutopilot) {
allowed = append(allowed, projectorID)
}

if perms.Has(perm.ProjectorCanSee) {
allowed = append(allowed, projectorID)
}
}
Expand Down
63 changes: 63 additions & 0 deletions internal/restrict/collection/projector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,69 @@ func TestProjectorModeA(t *testing.T) {
"projector/1/meeting_id: 30",
)

testCase(
"reference projector with projector.can_see",
t,
f,
true,
`
projector/1:
meeting_id: 30
used_as_reference_projector_meeting_id: 30
`,
withPerms(30, perm.ProjectorCanSee),
)

testCase(
"reference projector with meeting.can_see_autopilot",
t,
f,
true,
`
projector/1:
meeting_id: 30
used_as_reference_projector_meeting_id: 30
`,
withPerms(30, perm.MeetingCanSeeAutopilot),
)

testCase(
"reference projector with no perms",
t,
f,
false,
`
projector/1:
meeting_id: 30
used_as_reference_projector_meeting_id: 30
`,
)

testCase(
"not reference projector with meeting.can_see_autopilot",
t,
f,
false,
`
projector/1/meeting_id: 30
`,
withPerms(30, perm.MeetingCanSeeAutopilot),
)

testCase(
"reference projector with meeting.can_see_autopilot but internal",
t,
f,
false,
`
projector/1:
meeting_id: 30
used_as_reference_projector_meeting_id: 30
is_internal: true
`,
withPerms(30, perm.MeetingCanSeeAutopilot),
)

testCase(
"can see with internal",
t,
Expand Down
Loading
Loading