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

1060 implement permission system #1066

Closed
wants to merge 15 commits into from
135 changes: 135 additions & 0 deletions backend/root/utils/compute_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from typing import Generic, TypeVar, Dict, Set


T = TypeVar('T')


class Node(Generic[T]):
def __init__(self, data: T) -> None:
self.data: T = data
self.children: Set[Node[T]] = set()

def __str__(self) -> str:
return self.data


def dfs(graf: Set[Node]) -> Dict[Node, Set[Node]]:
# Initialize
reachable_nodes = {node: set() for node in graf}
for node in graf:
reachable_nodes[node].add(node)
# Do search
for node in graf:
stack = [node]
while stack:
current_node = stack.pop()
for child in current_node.children:
if len(reachable_nodes[child]) > 1:
# Avoid recomputing reachable nodes for child if it has already been computed
for reachable_node in reachable_nodes[child]:
reachable_nodes[node].add(reachable_node)
if child not in reachable_nodes[node]:
reachable_nodes[node].add(child)
stack.append(child)

return reachable_nodes


node1 = Node(1)
node2 = Node(2)
node3 = Node(3)

node1.children.add(node2)
node2.children.add(node3)

graf: set[Node[int]] = set()
graf.add(node1)
graf.add(node2)
graf.add(node3)

# print(dfs(graf))


class Permissions:
# FIX: permissions added multipletimes.
def __init__(self, dictionary):
self.dict = dictionary
self.index_array = list(dictionary.keys())

def __getitem__(self, key):
return self.dict[key]

def __str__(self):
return str(self.dict)

def get(self, index):
return self.dict[self.index_array[index]]

def set(self, key, value):
self.dict[key] = value

def get_index_array(self):
return self.index_array

def clean(self):
for key, value in self.dict.items():
self.dict[key] = ''.join(sorted(set(value)))


class Graph:
def __init__(self, vertices):
self.V = vertices

def printAdjMatrix(self, reach):
print('Following matrix transitive closure of the given graph ')
for i in range(self.V):
for j in range(self.V):
if i == j:
print('%7d\t' % (1), end=' ')
else:
print('%7d\t' % (reach[i][j]), end=' ')
print()

def compute_permissions(self, graph, permissions):
reach = [i[:] for i in graph]
index_array = permissions.get_index_array()

for k in range(self.V):
for i in range(self.V):
for j in range(self.V):
reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j])
if reach[i][j] == 1:
permissions.set(
index_array[j],
permissions.get(j) + permissions[index_array[i]],
)

self.printAdjMatrix(reach)
print('')

permissions.clean()
print(permissions)

return permissions


g = Graph(5)

graph = [
[1, 0, 1, 0, 0],
[0, 1, 1, 0, 1],
[0, 0, 1, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1],
]

p = Permissions(
{
'Ansatt': 'B',
'Hest': 'A',
'Mellomleder': 'C',
'Sjef': 'D',
'Baltazar': 'E',
}
)
# g.compute_permissions(graph, p)
71 changes: 15 additions & 56 deletions backend/samfundet/admin.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
from __future__ import annotations

from guardian import models as guardian_models

from django.urls import reverse
from django.contrib import admin
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import Group, Permission
from django.contrib.auth.models import Group
from django.contrib.admin.models import LogEntry
from django.contrib.sessions.models import Session
from django.contrib.contenttypes.models import ContentType

from root.utils.routes import admin__samfundet_recruitmentadmission_change
from root.custom_classes.admin_classes import CustomBaseAdmin, CustomGuardedUserAdmin, CustomGuardedGroupAdmin, CustomGuardedModelAdmin
from root.custom_classes.admin_classes import CustomBaseAdmin, CustomGuardedUserAdmin, CustomGuardedModelAdmin

from .models.event import Event, EventGroup, EventRegistration
from .models.general import (
Tag,
Gang,
Menu,
Role,
User,
Image,
Merch,
Expand Down Expand Up @@ -72,6 +71,15 @@
admin.site.register(Occupiedtimeslot)


@admin.register(Role)
class Role(CustomGuardedModelAdmin):
sortable_by = ['id', 'name']
list_display = ['id', 'name']
search_fields = ['id', 'name']
list_display_links = ['id', 'name']
filter_horizontal = ['ownes']


@admin.register(User)
class UserAdmin(CustomGuardedUserAdmin):
sortable_by = [
Expand Down Expand Up @@ -104,10 +112,11 @@ class UserAdmin(CustomGuardedUserAdmin):
]
list_display_links = ['id', 'username']
list_select_related = True
filter_horizontal = ['role']

@admin.display(empty_value='all')
def group_memberships(self, obj: User) -> int:
n: int = obj.groups.all().count()
n: int = obj.role.all().count()
return n

fieldsets = (
Expand All @@ -120,8 +129,7 @@ def group_memberships(self, obj: User) -> int:
'is_active',
'is_staff',
'is_superuser',
'groups',
'user_permissions',
'role',
),
},
),
Expand All @@ -138,31 +146,6 @@ def group_memberships(self, obj: User) -> int:
)


@admin.register(Group)
class GroupAdmin(CustomGuardedGroupAdmin):
sortable_by = ['id', 'name']
list_display = ['id', 'name', 'members']
list_display_links = ['id', 'name']
list_select_related = True

def members(self, obj: Group) -> int:
n: int = obj.user_set.all().count()
return n


@admin.register(Permission)
class PermissionAdmin(CustomGuardedModelAdmin):
# ordering = []
sortable_by = ['id', 'codename', 'content_type']
# list_filter = []
list_display = ['id', '__str__', 'codename', 'content_type']
search_fields = ['name', 'codename', 'content_type__app_label', 'content_type__model']
# filter_horizontal = []
list_display_links = ['id', '__str__']
autocomplete_fields = ['content_type']
list_select_related = True


@admin.register(ContentType)
class ContentTypeAdmin(CustomGuardedModelAdmin):
# ordering = []
Expand Down Expand Up @@ -205,30 +188,6 @@ class SessionAdmin(CustomGuardedModelAdmin):
### End: Django models ###


### Guardian models ###
@admin.register(guardian_models.GroupObjectPermission)
class GroupObjectPermissionAdmin(CustomGuardedModelAdmin):
list_display = ['id', '__str__', 'permission', 'group', 'content_type']
list_display_links = ['id', '__str__']


@admin.register(guardian_models.UserObjectPermission)
class UserObjectPermissionAdmin(CustomGuardedModelAdmin):
ordering = ['user']
sortable_by = ['id', 'user', 'permission', 'content_type']
# list_filter = [] # TODO
_user_search_fields = UserAdmin.custom_search_fields(prefix='user')
list_display = ['id', '__str__', 'user', 'permission', 'content_type']
search_fields = [*_user_search_fields]
# filter_horizontal = [] # TODO
list_display_links = ['id', '__str__']
autocomplete_fields = ['user', 'permission', 'content_type']
list_select_related = True


### End: Guardian models ###


### Our models ###
@admin.register(Campus)
class CampusAdmin(CustomGuardedModelAdmin):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 5.0.2 on 2024-04-11 17:54

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('samfundet', '0011_merch_merchvariation'),
]

operations = [
migrations.CreateModel(
name='PermissionGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('version', models.PositiveIntegerField(blank=True, default=0, editable=False, null=True)),
('created_at', models.DateTimeField(blank=True, editable=False, null=True)),
('updated_at', models.DateTimeField(blank=True, editable=False, null=True)),
('name', models.CharField(blank=True, max_length=64, unique=True)),
('admin_perms', models.ManyToManyField(blank=True, to='samfundet.permissiongroup')),
('created_by', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='samfundet.permissiongroup')),
('updated_by', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'PermissionGroup',
'verbose_name_plural': 'PermissionGroups',
},
),
migrations.AddField(
model_name='user',
name='permission_groups',
field=models.ManyToManyField(blank=True, to='samfundet.permissiongroup'),
),
]
Loading