diff --git a/backend/apps/ecommerce/tests.py b/backend/apps/ecommerce/tests.py index a161cad1b..8846542ca 100644 --- a/backend/apps/ecommerce/tests.py +++ b/backend/apps/ecommerce/tests.py @@ -112,7 +112,7 @@ def setUp(self) -> None: MembershipFactory( user=self.staff_user, organization=self.organization, - group=self.organization.primary_group, + group=self.organization.member_group, ) self.total_quantity = 5 self.max_buyable_quantity = 2 diff --git a/backend/apps/forms/signals.py b/backend/apps/forms/signals.py index d94907b67..ffe107665 100644 --- a/backend/apps/forms/signals.py +++ b/backend/apps/forms/signals.py @@ -9,6 +9,6 @@ def handle_new_form(sender, instance: Form, created: bool, **kwargs) -> None: if created: perms = ["forms.manage_form", "forms.change_form", "forms.delete_form"] - group = instance.organization.hr_group.group + group = instance.organization.admin_group.group for perm in perms: assign_perm(perm, group, instance) diff --git a/backend/apps/forms/tests.py b/backend/apps/forms/tests.py index b079384a2..8090061b7 100644 --- a/backend/apps/forms/tests.py +++ b/backend/apps/forms/tests.py @@ -31,7 +31,7 @@ def setUp(self) -> None: MembershipFactory( user=self.authorized_user, organization=self.organization, - group=self.organization.hr_group, + group=self.organization.admin_group, ) # Create the form diff --git a/backend/apps/organizations/migrations/0026_auto_20210426_1802.py b/backend/apps/organizations/migrations/0026_auto_20210426_1802.py index 14c6031c3..c01b9bd7c 100644 --- a/backend/apps/organizations/migrations/0026_auto_20210426_1802.py +++ b/backend/apps/organizations/migrations/0026_auto_20210426_1802.py @@ -18,7 +18,8 @@ def set_primary_groups(apps, schema_editor): created = True if organization.hr_group is None: hr_group = ResponsibleGroup.objects.create( - name="HR", description=f"HR-gruppen til {organization.name}. Tillatelser for å se og behandle søknader." + name="HR", + description=f"HR-gruppen til {organization.name}. Tillatelser for å se og behandle søknader.", ) organization.hr_group = hr_group created = True diff --git a/backend/apps/organizations/migrations/0034_alter_organization_options.py b/backend/apps/organizations/migrations/0034_alter_organization_options.py index 80be66ee5..997b0f88a 100644 --- a/backend/apps/organizations/migrations/0034_alter_organization_options.py +++ b/backend/apps/organizations/migrations/0034_alter_organization_options.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.16 on 2023-01-23 18:47 +# Generated by Django 3.2.16 on 2022-11-21 20:19 from django.db import migrations diff --git a/backend/apps/organizations/models.py b/backend/apps/organizations/models.py index d0f66d32a..3c4476091 100644 --- a/backend/apps/organizations/models.py +++ b/backend/apps/organizations/models.py @@ -4,7 +4,7 @@ from django.db import models from django.db.models import UniqueConstraint -from apps.permissions.constants import HR_TYPE, PRIMARY_TYPE +from apps.permissions.constants import ADMIN_GROUP_TYPE, MEMBER_GROUP_TYPE from apps.permissions.models import ResponsibleGroup @@ -28,7 +28,8 @@ class Organization(models.Model): # Permission groups # All members are added to the primary group # Members can be added to groups programatically - # The HR-group has the "forms.manage_form" permission, allowing them to view and manage responses to e.g. listings. + # The ADMIN-group has the "forms.manage_form" permission, allowing them to view and manage responses to e.g. + # listings. # The primary group is intended to act as a group for organizations who need any kind of # special permission, e.g. hyttestyret # Or if we wish to limit the creation of events or listings to certain organizations. @@ -42,16 +43,16 @@ class Organization(models.Model): ) @property - def hr_group(self) -> Optional["ResponsibleGroup"]: + def admin_group(self) -> Optional["ResponsibleGroup"]: try: - return self.permission_groups.get(group_type=HR_TYPE) + return self.permission_groups.get(group_type=ADMIN_GROUP_TYPE) except ResponsibleGroup.DoesNotExist: return None @property - def primary_group(self) -> Optional["ResponsibleGroup"]: + def member_group(self) -> Optional["ResponsibleGroup"]: try: - return self.permission_groups.get(group_type=PRIMARY_TYPE) + return self.permission_groups.get(group_type=MEMBER_GROUP_TYPE) except ResponsibleGroup.DoesNotExist: return None diff --git a/backend/apps/organizations/signals.py b/backend/apps/organizations/signals.py index d7dfb07a5..0d7ab50eb 100644 --- a/backend/apps/organizations/signals.py +++ b/backend/apps/organizations/signals.py @@ -7,11 +7,11 @@ from apps.organizations.models import Membership, Organization from apps.permissions.constants import ( - HR_GROUP_NAME, - HR_TYPE, + ADMIN_GROUP_NAME, + ADMIN_GROUP_TYPE, ORGANIZATION, - PRIMARY_GROUP_NAME, - PRIMARY_TYPE, + MEMBER_GROUP_NAME, + MEMBER_GROUP_TYPE, ) from apps.permissions.models import ResponsibleGroup @@ -19,7 +19,7 @@ @receiver(post_save, sender=Membership) def handle_new_member(instance: Membership, **kwargs): optional_group: Optional[ResponsibleGroup] = instance.group - group: Group = instance.organization.primary_group.group + group: Group = instance.organization.member_group.group org_group: Group = Group.objects.get(name=ORGANIZATION) user = instance.user user.groups.add(org_group) @@ -31,7 +31,7 @@ def handle_new_member(instance: Membership, **kwargs): @receiver(pre_delete, sender=Membership) def handle_removed_member(instance: Membership, **kwargs): - group: Group = instance.organization.primary_group.group + group: Group = instance.organization.member_group.group org_group: Group = Group.objects.get(name=ORGANIZATION) user = instance.user if group: @@ -44,19 +44,19 @@ def handle_removed_member(instance: Membership, **kwargs): @receiver(post_save, sender=Organization) def create_default_groups(instance: Organization, created, **kwargs): """ - Creates and assigns a primary group and HR group to members of the organization. + Creates and assigns a primary group and ADMIN group to members of the organization. """ if created: ResponsibleGroup.objects.create( - name=PRIMARY_GROUP_NAME, + name=f"{instance.name}:{MEMBER_GROUP_NAME}", description=f"Medlemmer av {instance.name}.", organization=instance, - group_type=PRIMARY_TYPE, + group_type=MEMBER_GROUP_TYPE, ) - hr_group = ResponsibleGroup.objects.create( - name=HR_GROUP_NAME, - description=f"HR-gruppen til {instance.name}. Tillatelser for å se og behandle søknader.", + admin_group = ResponsibleGroup.objects.create( + name=f"{instance.name}:{ADMIN_GROUP_NAME}", + description=f"ADMIN-gruppen til {instance.name}. Tillatelser for å se og behandle søknader og medlemmer.", organization=instance, - group_type=HR_TYPE, + group_type=ADMIN_GROUP_TYPE, ) - assign_perm("forms.add_form", hr_group.group) + assign_perm("forms.add_form", admin_group.group) diff --git a/backend/apps/organizations/types.py b/backend/apps/organizations/types.py index 0afeb43cd..2c9f10b4e 100644 --- a/backend/apps/organizations/types.py +++ b/backend/apps/organizations/types.py @@ -14,8 +14,8 @@ class OrganizationType(DjangoObjectType): absolute_slug = graphene.String() listings = graphene.List(NonNull(ListingType)) - primary_group = graphene.Field(source="primary_group", type=ResponsibleGroupType) - hr_group = graphene.Field(source="hr_group", type=ResponsibleGroupType) + member_group = graphene.Field(source="member_group", type=ResponsibleGroupType) + admin_group = graphene.Field(source="admin_group", type=ResponsibleGroupType) class Meta: model = Organization @@ -30,8 +30,8 @@ class Meta: "users", "events", "logo_url", - "primary_group", - "hr_group", + "member_group", + "admin_group", ] @staticmethod diff --git a/backend/apps/permissions/constants.py b/backend/apps/permissions/constants.py index 230f8a70c..77d632f61 100644 --- a/backend/apps/permissions/constants.py +++ b/backend/apps/permissions/constants.py @@ -3,14 +3,14 @@ DefaultPermissionsType = Final[list[tuple[str, str]]] # Default ResponsibleGroup types -PRIMARY_TYPE: Literal["PRIMARY"] = "PRIMARY" -HR_TYPE: Literal["HR"] = "HR" +MEMBER_GROUP_TYPE: Literal["MEMBER"] = "MEMBER" +ADMIN_GROUP_TYPE: Literal["ADMIN"] = "ADMIN" ORGANIZATION: Final = "Organization member" INDOK: Final = "Indøk" REGISTERED_USER: Final = "Registered user" -PRIMARY_GROUP_NAME: Final = "Medlem" -HR_GROUP_NAME: Final = "HR" +MEMBER_GROUP_NAME: Final = "Medlem" +ADMIN_GROUP_NAME: Final = "Administrator" DEFAULT_ORGANIZATION_PERMISSIONS: DefaultPermissionsType = [ ("events", "add_event"), diff --git a/backend/apps/permissions/migrations/0003_auto_20210824_1213.py b/backend/apps/permissions/migrations/0003_auto_20210824_1213.py index 9834f6dbd..6195edc49 100644 --- a/backend/apps/permissions/migrations/0003_auto_20210824_1213.py +++ b/backend/apps/permissions/migrations/0003_auto_20210824_1213.py @@ -4,7 +4,7 @@ from django.db import migrations from django.db.models.query_utils import Q -from apps.permissions.constants import PRIMARY_GROUP_NAME, HR_GROUP_NAME +from apps.permissions.constants import MEMBER_GROUP_NAME, ADMIN_GROUP_NAME if TYPE_CHECKING: from apps.organizations import models @@ -19,14 +19,14 @@ def improve_group_legibility(apps, _): responsible_group: "ResponsibleGroup" = group.responsiblegroup try: organization: "models.Organization" = Organization.objects.get( - Q(primary_group=responsible_group) | Q(hr_group=responsible_group) + Q(member_group=responsible_group) | Q(admin_group=responsible_group) ) responsible_group_name = responsible_group.name - if organization.primary_group == responsible_group: - responsible_group_name = PRIMARY_GROUP_NAME - elif organization.hr_group == responsible_group: - responsible_group_name = HR_GROUP_NAME + if organization.member_group == responsible_group: + responsible_group_name = MEMBER_GROUP_NAME + elif organization.admin_group == responsible_group: + responsible_group_name = ADMIN_GROUP_NAME if responsible_group.name != responsible_group_name: responsible_group.name = responsible_group_name responsible_group.save() @@ -50,7 +50,7 @@ def reverse_legible_group_names(apps, _): responsible_group = group.responsiblegroup try: organization = responsible_group.organization - if organization.primary_group == responsible_group: + if organization.member_group == responsible_group: responsible_group.name = organization.name responsible_group.save() except Organization.DoesNotExist: diff --git a/backend/apps/permissions/migrations/0005_auto_20210824_1446.py b/backend/apps/permissions/migrations/0005_auto_20210824_1446.py index 9cb248bc7..afb375654 100644 --- a/backend/apps/permissions/migrations/0005_auto_20210824_1446.py +++ b/backend/apps/permissions/migrations/0005_auto_20210824_1446.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Type from django.db import migrations -from apps.permissions.constants import HR_TYPE, PRIMARY_TYPE +from apps.permissions.constants import ADMIN_GROUP_TYPE, MEMBER_GROUP_TYPE if TYPE_CHECKING: from apps.organizations import models as org_models @@ -15,22 +15,22 @@ def move_permission_groups_to_fk(apps, _): Organization: Type["org_models.Organization"] = apps.get_model("organizations", "Organization") for organization in Organization.objects.all(): - primary_group = organization.primary_group - hr_group = organization.hr_group + member_group = organization.member_group + admin_group = organization.admin_group - if primary_group and hr_group: - primary_group.group_type = PRIMARY_TYPE - hr_group.group_type = HR_TYPE + if member_group and admin_group: + member_group.group_type = MEMBER_GROUP_TYPE + admin_group.group_type = ADMIN_GROUP_TYPE # Name as of this migration - primary_group.temp_organization = organization - hr_group.temp_organization = organization + member_group.temp_organization = organization + admin_group.temp_organization = organization - primary_group.save() - hr_group.save() + member_group.save() + admin_group.save() - organization.primary_group = None - organization.hr_group = None + organization.member_group = None + organization.admin_group = None organization.save() # Delete orphan responsible groups @@ -43,10 +43,12 @@ def move_permission_groups_to_one_to_one_field(apps, _): organization: "org_models.Organization" for organization in Organization.objects.all(): - organization.primary_group = ResponsibleGroup.objects.get( - temp_organization=organization, group_type=PRIMARY_TYPE + organization.member_group = ResponsibleGroup.objects.get( + temp_organization=organization, group_type=MEMBER_GROUP_TYPE + ) + organization.admin_group = ResponsibleGroup.objects.get( + temp_organization=organization, group_type=ADMIN_GROUP_TYPE ) - organization.hr_group = ResponsibleGroup.objects.get(temp_organization=organization, group_type=HR_TYPE) organization.save() diff --git a/backend/apps/permissions/migrations/0034_auto_20221114_1854.py b/backend/apps/permissions/migrations/0034_auto_20221114_1854.py new file mode 100644 index 000000000..423e043fc --- /dev/null +++ b/backend/apps/permissions/migrations/0034_auto_20221114_1854.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.16 on 2022-11-14 17:54 + +from django.db import migrations +from apps.permissions.constants import ADMIN_GROUP_TYPE, MEMBER_GROUP_TYPE + + +def migrate_org_groups(apps, schema_editor): + ResponsibleGroup = apps.get_model("permissions", "ResponsibleGroup") + for responsible_group in ResponsibleGroup.objects.all(): + if responsible_group.name == "HR": + # ResponsibleGroup names format is "Organization:Type" (ex "Rubberdøk:ADMIN") + # Type is either "ADMIN" or "MEMBER" + # ResponsibleGroup has a group field which is a django.contrib.auth.models.Group with outdated names + # Change the Type in group name to "ADMIN" or "MEMBER" depending on the ResponsibleGroup name (e.g. "Organization:HR:uuid" -> "Organization:ADMIN:uuid") + # Change ResponsibleGroup.group_type from "HR" or "PRIMARY" to "ADMIN" or "MEMBER" + responsible_group.name = f"{responsible_group.organization.name}:{ADMIN_GROUP_TYPE}" + responsible_group.group.name = ( + f"{responsible_group.organization.name}:{ADMIN_GROUP_TYPE}:git{responsible_group.uuid}" + ) + responsible_group.group_type = ADMIN_GROUP_TYPE + responsible_group.save() + if responsible_group.name == "Medlem": + responsible_group.name = f"{responsible_group.organization.name}:{MEMBER_GROUP_TYPE}" + responsible_group.group.name = ( + f"{responsible_group.organization.name}:{MEMBER_GROUP_TYPE}:{responsible_group.uuid}" + ) + responsible_group.group_type = MEMBER_GROUP_TYPE + responsible_group.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("organizations", "0033_merge_0031_auto_20210909_1813_0032_auto_20210824_1457"), + ] + + operations = [migrations.RunPython(migrate_org_groups)] diff --git a/backend/apps/permissions/migrations/0035_merge_20221117_1825.py b/backend/apps/permissions/migrations/0035_merge_20221117_1825.py new file mode 100644 index 000000000..e110603b3 --- /dev/null +++ b/backend/apps/permissions/migrations/0035_merge_20221117_1825.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.16 on 2022-11-17 17:25 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("permissions", "0011_merge_0004_auto_20210824_2126_0010_auto_20210824_1546"), + ("permissions", "0034_auto_20221114_1854"), + ] + + operations = [] diff --git a/backend/apps/permissions/signals.py b/backend/apps/permissions/signals.py index fa2ae43fd..cc63f27fc 100644 --- a/backend/apps/permissions/signals.py +++ b/backend/apps/permissions/signals.py @@ -24,8 +24,7 @@ def create_named_group(sender, instance: ResponsibleGroup, **kwargs): try: instance.group except ObjectDoesNotExist: - prefix: str = instance.organization.name - group = Group.objects.create(name=f"{prefix}:{instance.name}:{uuid4().hex}") + group = Group.objects.create(name=f"{instance.name}:{uuid4().hex}") instance.group = group diff --git a/backend/schema.json b/backend/schema.json index 7ca001511..0061db6fa 100644 --- a/backend/schema.json +++ b/backend/schema.json @@ -20,11 +20,7 @@ } ], "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], + "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "name": "include" }, { @@ -45,11 +41,7 @@ } ], "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], + "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "name": "skip" } ], @@ -1581,7 +1573,7 @@ "deprecationReason": null, "description": null, "isDeprecated": false, - "name": "primaryGroup", + "name": "memberGroup", "type": { "kind": "OBJECT", "name": "ResponsibleGroupType", @@ -1593,7 +1585,7 @@ "deprecationReason": null, "description": null, "isDeprecated": false, - "name": "hrGroup", + "name": "adminGroup", "type": { "kind": "OBJECT", "name": "ResponsibleGroupType", @@ -10900,4 +10892,4 @@ ] } } -} \ No newline at end of file +} diff --git a/frontend/src/components/pages/organization/OrgMembers.tsx b/frontend/src/components/pages/organization/OrgMembers.tsx index 60bbbe27b..5b8bbdf6e 100644 --- a/frontend/src/components/pages/organization/OrgMembers.tsx +++ b/frontend/src/components/pages/organization/OrgMembers.tsx @@ -77,12 +77,12 @@ export const OrgMembers: React.FC = ({ organization }) => { {membership.user.firstName} {membership.user.lastName} - {membership?.group?.uuid == organization.hrGroup?.uuid ? "Administrator" : "Medlem"} + {membership?.group?.uuid == organization.adminGroup?.uuid ? "Administrator" : "Medlem"}