Skip to content

Commit

Permalink
Proxy permission and role model (#749)
Browse files Browse the repository at this point in the history
* new proxy Permission model

* Role Model
  • Loading branch information
dpgraham4401 authored Jul 11, 2024
1 parent d530db1 commit f677506
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 2 deletions.
4 changes: 3 additions & 1 deletion server/apps/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from apps.profile.models import Profile, RcrainfoProfile, RcrainfoSiteAccess

from .models import TrakUser
from .models import Permission, Role, TrakUser


class HiddenListView(admin.ModelAdmin):
Expand Down Expand Up @@ -73,3 +73,5 @@ def api_user(self, profile: RcrainfoProfile) -> bool:

admin.site.register(Profile)
admin.site.unregister(DRFToken)
admin.site.register(Permission)
admin.site.register(Role)
32 changes: 32 additions & 0 deletions server/apps/core/migrations/0002_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 5.0.6 on 2024-07-11 19:06

import django.contrib.auth.models
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('core', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Permission',
fields=[
],
options={
'verbose_name': 'Permission',
'verbose_name_plural': 'Permissions',
'ordering': ['name'],
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('auth.permission',),
managers=[
('objects', django.contrib.auth.models.PermissionManager()),
],
),
]
26 changes: 26 additions & 0 deletions server/apps/core/migrations/0003_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.0.6 on 2024-07-11 19:39

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0002_permission'),
]

operations = [
migrations.CreateModel(
name='Role',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=150, unique=True, verbose_name='name')),
('permissions', models.ManyToManyField(to='core.permission', verbose_name='permissions')),
],
options={
'verbose_name': 'Role',
'verbose_name_plural': 'Roles',
'ordering': ['name'],
},
),
]
47 changes: 46 additions & 1 deletion server/apps/core/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import uuid

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import AbstractUser, Group
from django.contrib.auth.models import Permission as DjangoPermission
from django.db import models
from django.utils.translation import gettext_lazy as _


class TrakUser(AbstractUser):
Expand All @@ -17,3 +19,46 @@ class Meta:
editable=False,
default=uuid.uuid4,
)


class Permission(DjangoPermission):
"""Haztrak proxy permission model used for our custom object level permissions."""

class Meta:
proxy = True
verbose_name = "Permission"
verbose_name_plural = "Permissions"
ordering = ["name"]

@property
def app_label(self):
return self.content_type.app_label

@property
def model_name(self):
return self.content_type.model

def __str__(self):
return f"{self.content_type.name} | {self.name}"


class Role(models.Model):
"""A job/function within the system that can assigned to users to grant them permissions."""

class Meta:
verbose_name = _("Role")
verbose_name_plural = _("Roles")
ordering = ["name"]

name = models.CharField(
_("name"),
max_length=150,
unique=True,
)
permissions = models.ManyToManyField(
Permission,
verbose_name=_("permissions"),
)

def __str__(self):
return f"{self.name}"
22 changes: 22 additions & 0 deletions server/apps/core/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from typing import Dict, List, Optional

import pytest
from django.contrib.contenttypes.models import ContentType
from faker import Faker

from apps.core.models import Permission
from apps.rcrasite.models import RcraSiteType


Expand Down Expand Up @@ -40,3 +42,23 @@ def create_quicker_sign(
}

return create_quicker_sign


@pytest.fixture
def permission_factory(faker: Faker):
"""
Factory for creating dynamic permission data
"""

def create_permission(
name: str = faker.word(),
content_type_id: int = faker.random_int(min=1),
) -> Permission:
content_type = ContentType.objects.create(app_label=faker.word(), model=faker.word())
return Permission.objects.create(
name=name,
content_type=content_type,
content_type_id=content_type_id,
)

return create_permission
42 changes: 42 additions & 0 deletions server/apps/core/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import pytest
from django.contrib.contenttypes.models import ContentType

from apps.core.models import Permission, Role


class TestPermissionModel:
mock_app_label = "test_app"
mock_model = "test_model"

@pytest.fixture
def mock_content_type(self):
return ContentType.objects.create(app_label=self.mock_app_label, model=self.mock_model)

@pytest.mark.django_db
def test_saves_new_permissions(self, mock_content_type):
permission_name = "test_permission"
permission = Permission.objects.create(
content_type=mock_content_type, content_type_id=1, name=permission_name
)

saved_permission = Permission.objects.get(name=permission_name)

assert saved_permission.name == permission_name
assert saved_permission.id == permission.id


class TestRoleModel:
@pytest.mark.django_db
def test_role_with_multiple_permissions(self, permission_factory):
permission1 = permission_factory(content_type_id=1)
permission2 = permission_factory(content_type_id=2)
role = Role.objects.create(name="test_role")
role.permissions.add(permission1, permission2)
assert role.permissions.count() == 2
assert permission1 in role.permissions.all()
assert permission2 in role.permissions.all()

@pytest.mark.django_db
def test_role_str_representation(self):
role = Role.objects.create(name="test_role")
assert str(role) == "test_role"

0 comments on commit f677506

Please sign in to comment.