Skip to content

Commit

Permalink
New rule for derived motions (#1026)
Browse files Browse the repository at this point in the history
  • Loading branch information
ostcar authored Oct 15, 2024
1 parent 0b0c995 commit 6989b78
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 13 deletions.
61 changes: 50 additions & 11 deletions internal/restrict/collection/motion.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,27 @@ import (
//
// The user can see a motion if:
//
// The user has motion.can_see in the meeting, and
// For one `restriction` in the motion's state `state/restriction` field:
// If: `restriction` is `is_submitter`: The user needs to be a submitter of the motion
// Else: (a permission string): The user needs the permission
// And - for amendments (lead_motion_id != null) - the user can also see the lead motion.
// The user has motion.can_see in the meeting or
// for one of the motions in `motion/all_derived_motion_ids` the user has motion.can_see_origin in the corresponding meeting
//
// Mode A: The user can see the motion or can see a referenced motion in motion/all_origin_ids and motion/all_derived_motion_ids.
// and for one `restriction` in the motion's state `state/restriction` field:
// If: `restriction` is `is_submitter`: The user needs to be a submitter of the motion
// Else: (a permission string): The user needs the permission
//
// Mode B: The user has the permission motion.can_manage_metadata in the motion's meeting.
// and - for amendments (lead_motion_id != null) - the user can also see the lead motion.
//
// Mode A: The user can see the motion or can see a referenced motion in
// motion/all_origin_ids and motion/all_derived_motion_ids.
//
// Mode B: The user has the permission motion.can_manage_metadata in the
// motion's meeting.
//
// Mode C: The user can see the motion.
//
// Mode D: Never published to any user.
//
// Mode E: If the motion states is_internal is true the user needs the permission motion.can_manage_metadata otherwise same as Mode C
// Mode E: If the motion states is_internal is true the user needs the
// permission motion.can_manage_metadata otherwise same as Mode C
type Motion struct{}

// Name returns the collection name.
Expand Down Expand Up @@ -76,11 +82,44 @@ func (m Motion) see(ctx context.Context, ds *dsfetch.Fetch, motionIDs ...int) ([
return nil, fmt.Errorf("getting permissions: %w", err)
}

if !perms.Has(perm.MotionCanSee) {
return nil, nil
step1Allowed, err := eachCondition(ids, func(id int) (bool, error) {
if perms.Has(perm.MotionCanSee) {
return true, nil
}

derivedIDs, err := ds.Motion_AllDerivedMotionIDs(id).Value(ctx)
if err != nil {
return false, fmt.Errorf("fetching all_derived_ids: %w", err)
}

meetingIDs := make([]int, len(derivedIDs))
for i, derivedID := range derivedIDs {
ds.Motion_MeetingID(derivedID).Lazy(&meetingIDs[i])
}

if err := ds.Execute(ctx); err != nil {
return false, fmt.Errorf("fetching meeting ids from derived motions: %w", err)
}

for _, meetingID := range meetingIDs {
perms, err := perm.FromContext(ctx, meetingID)
if err != nil {
return false, fmt.Errorf("getting permission from derived motion meeting: %w", err)
}

if perms.Has(perm.MotionCanSeeOrigin) {
return true, nil
}
}

return false, nil

})
if err != nil {
return nil, fmt.Errorf("checking condition 1: %w", err)
}

return eachRelationField(ctx, ds.Motion_StateID, ids, func(stateID int, ids []int) ([]int, error) {
return eachRelationField(ctx, ds.Motion_StateID, step1Allowed, func(stateID int, ids []int) ([]int, error) {
restrictions, err := ds.MotionState_Restrictions(stateID).Value(ctx)
if err != nil {
return nil, fmt.Errorf("getting restrictions: %w", err)
Expand Down
37 changes: 35 additions & 2 deletions internal/restrict/collection/motion_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import (

// MotionState handels restrictions of the collection motion_state.
//
// The user can see a motion state if the user has motion.can_see.
// The user can see a motion state if the user has motion.can_see or see a
// motion in motion_state/motion_ids.
//
// Mode A: The user can see the motion state.
type MotionState struct{}
Expand Down Expand Up @@ -40,5 +41,37 @@ func (m MotionState) Modes(mode string) FieldRestricter {
}

func (m MotionState) see(ctx context.Context, ds *dsfetch.Fetch, motionStateIDs ...int) ([]int, error) {
return meetingPerm(ctx, ds, m, motionStateIDs, perm.MotionCanSee)
return eachMeeting(ctx, ds, m, motionStateIDs, func(meetingID int, motionStateIDs []int) ([]int, error) {
perms, err := perm.FromContext(ctx, meetingID)
if err != nil {
return nil, fmt.Errorf("getting permission: %w", err)
}

if perms.Has(perm.MotionCanSee) {
return motionStateIDs, nil
}

motionIDsList := make([][]int, len(motionStateIDs))
for i, id := range motionStateIDs {
ds.MotionState_MotionIDs(id).Lazy(&motionIDsList[i])
}
if err := ds.Execute(ctx); err != nil {
return nil, fmt.Errorf("fetching motion ids: %w", err)
}

allowed := make([]int, 0, len(motionStateIDs))
for i, motionIDs := range motionIDsList {
allowedMotions, err := Collection(ctx, Motion{}.Name()).Modes("C")(ctx, ds, motionIDs...)
if err != nil {
return nil, fmt.Errorf("check restriction of motions: %w", err)
}

if len(allowedMotions) > 0 {
allowed = append(allowed, motionStateIDs[i])
}
}

return allowed, nil
})

}
26 changes: 26 additions & 0 deletions internal/restrict/collection/motion_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,30 @@ func TestMotionStateModeA(t *testing.T) {
"motion_state/1/meeting_id: 30",
withPerms(30, perm.MotionCanSee),
)

testCase(
"can see motion",
t,
f,
true,
`---
motion:
1:
meeting_id: 30
state_id: 3
all_derived_motion_ids: [10]
10:
meeting_id: 31
state_id: 7
motion_state/3:
meeting_id: 30
motion_ids: [1]
motion_state/7/id: 7
`,
withPerms(31, perm.MotionCanSeeOrigin),
withElementID(3),
)
}
42 changes: 42 additions & 0 deletions internal/restrict/collection/motion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,48 @@ func TestMotionModeC(t *testing.T) {
withPerms(30, perm.MotionCanSee),
)

testCase(
"motion/all_derived_motion_ids but not motion.can_see_origin",
t,
f,
false,
`---
motion:
1:
meeting_id: 30
state_id: 3
all_derived_motion_ids: [10]
10:
meeting_id: 31
state_id: 3
motion_state/3/id: 3
`,
withPerms(31, perm.MotionCanSee),
)

testCase(
"motion/all_derived_motion_ids with motion.can_see_origin",
t,
f,
true,
`---
motion:
1:
meeting_id: 30
state_id: 3
all_derived_motion_ids: [10]
10:
meeting_id: 31
state_id: 3
motion_state/3/id: 3
`,
withPerms(31, perm.MotionCanSeeOrigin),
)

testCase(
"motion.can_see with restrict is_submitter",
t,
Expand Down

0 comments on commit 6989b78

Please sign in to comment.