From e244ad36c9171e249b213912acf5d509b39c5702 Mon Sep 17 00:00:00 2001 From: Victoria Earl Date: Thu, 31 Oct 2024 20:47:38 -0400 Subject: [PATCH] Add better access controls for groups Fixes https://magfest.atlassian.net/browse/MAGDEV-1343. Also fixes a bug where, if you were linked to a group, you could view the group regardless of your permissions. --- uber/models/__init__.py | 33 +++++++++++++++++++++++++------ uber/models/attendee.py | 2 +- uber/models/group.py | 24 ++++++++++++++++++++++ uber/site_sections/group_admin.py | 3 +++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/uber/models/__init__.py b/uber/models/__init__.py index 9a42d5183..b58cf24ca 100644 --- a/uber/models/__init__.py +++ b/uber/models/__init__.py @@ -803,6 +803,19 @@ def admin_attendee_max_access(self, attendee, read_only=True): if attendee.access_sections: return max([admin.max_level_access(section, read_only=read_only) for section in attendee.access_sections]) + + def admin_group_max_access(self, group, read_only=True): + admin = self.current_admin_account() + if not admin: + return 0 + + if admin.full_registration_admin or group.creator == admin.attendee or \ + (admin.attendee.group and admin.attendee.group == group) or group.is_new: + return AccessGroup.FULL + + if group.access_sections: + return max([admin.max_level_access(section, + read_only=read_only) for section in group.access_sections]) def viewable_groups(self): from uber.models import Group, GuestGroup @@ -821,14 +834,22 @@ def viewable_groups(self): if val.lower() + '_admin' in admin.read_or_write_access_set: subqueries.append( self.query(Group).join( - GuestGroup, Group.id == GuestGroup.group_id).filter(GuestGroup.group_type == key - ) - ) + GuestGroup, Group.id == GuestGroup.group_id).filter( + GuestGroup.group_type == key)) if 'dealer_admin' in admin.read_or_write_access_set: - subqueries.append( - self.query(Group).filter(Group.is_dealer) - ) + subqueries.append(self.query(Group).filter(Group.is_dealer)) + + if 'shifts_admin' in admin.read_or_write_access_set: + subqueries.append(self.query(Group).join(Group.leader).filter( + Attendee.badge_type == c.CONTRACTOR_BADGE)) + staff_groups = self.query(Group).join(Group.leader).filter(Attendee.badge_type == c.STAFF_BADGE) + if admin.full_shifts_admin: + subqueries.append(staff_groups) + else: + for dept_membership in admin.attendee.dept_memberships_with_inherent_role: + subqueries.append(staff_groups.filter( + Attendee.dept_memberships.any(department_id=dept_membership.department_id))) return subqueries[0].union(*subqueries[1:]) diff --git a/uber/models/attendee.py b/uber/models/attendee.py index 71ee10161..9ca285787 100644 --- a/uber/models/attendee.py +++ b/uber/models/attendee.py @@ -732,7 +732,7 @@ def access_sections(self): if (self.group and self.group.guest and self.group.guest.group_type == c.BAND) \ or (self.badge_type == c.GUEST_BADGE and c.BAND in self.ribbon_ints): section_list.append('band_admin') - if (self.group and self.group.guest and self.group.guest.group_type == c.GUEST) \ + if (self.group and self.group.guest and self.group.guest.group_type not in [c.BAND, c.MIVS]) \ or (self.badge_type == c.GUEST_BADGE and c.BAND not in self.ribbon_ints): section_list.append('guest_admin') if c.PANELIST_RIBBON in self.ribbon_ints: diff --git a/uber/models/group.py b/uber/models/group.py index 205af74f3..b504efdcf 100644 --- a/uber/models/group.py +++ b/uber/models/group.py @@ -236,6 +236,30 @@ def attendees_have_badges(cls): return and_(cls.is_valid, or_(cls.is_dealer == False, cls.status.in_([c.APPROVED, c.SHARED]))) # noqa: E712 + @property + def access_sections(self): + """ + Returns what site sections a group 'belongs' to based on their properties. + We use this list to determine which admins can view the group. + In some cases, we rely on the group's leader to tell us what kind of group this is. + """ + section_list = [] + if self.leader: + if self.leader.badge_type in [c.STAFF_BADGE, c.CONTRACTOR_BADGE]: + section_list.append('shifts_admin') + if c.PANELIST_RIBBON in self.leader.ribbon_ints: + section_list.append('panels_admin') + if self.is_dealer: + section_list.append('dealer_admin') + if self.guest: + if self.guest.group_type == c.BAND: + section_list.append('band_admin') + elif self.guest.group_type == c.MIVS: + section_list.append('mivs_admin') + else: + section_list.append('guest_admin') + return section_list + @property def new_ribbon(self): return c.DEALER_RIBBON if self.is_dealer else '' diff --git a/uber/site_sections/group_admin.py b/uber/site_sections/group_admin.py index 4fff46583..395bafa12 100644 --- a/uber/site_sections/group_admin.py +++ b/uber/site_sections/group_admin.py @@ -75,6 +75,9 @@ def form(self, session, new_dealer='', message='', **params): if params.get('id') not in [None, '', 'None']: group = session.group(params.get('id')) + if not session.admin_group_max_access(group): + raise HTTPRedirect('index?message={}', f"You are not allowed to view this group. If you think this is an error, \ + please email us at {c.DEVELOPER_EMAIL}") if cherrypy.request.method == 'POST': receipt_items = ReceiptManager.auto_update_receipt(group, session.get_receipt_by_model(group), params.copy()) session.add_all(receipt_items)