diff --git a/aleksis/core/schema/__init__.py b/aleksis/core/schema/__init__.py index deab0e28b5d93e854a020aad687a618817196536..901c4d8a37cccb574425ccb743bd47839e9e0d16 100644 --- a/aleksis/core/schema/__init__.py +++ b/aleksis/core/schema/__init__.py @@ -9,7 +9,7 @@ from haystack.inputs import AutoQuery from haystack.query import SearchQuerySet from haystack.utils.loading import UnifiedIndex -from ..models import CustomMenu, DynamicRoute, Notification, PDFFile, Person, TaskUserAssignment +from ..models import CustomMenu, DynamicRoute, Notification, PDFFile, Person, TaskUserAssignment, Room from ..util.apps import AppConfig from ..util.core_helpers import get_allowed_object_ids, get_app_module, get_app_packages, has_person from .celery_progress import CeleryProgressFetchedMutation, CeleryProgressType @@ -21,6 +21,7 @@ from .message import MessageType from .notification import MarkNotificationReadMutation, NotificationType from .pdf import PDFFileType from .person import PersonMutation, PersonType +from .room import RoomType, RoomBatchPatchMutation, RoomCreateMutation from .school_term import SchoolTermType # noqa from .search import SearchResultType from .system_properties import SystemPropertiesType @@ -59,6 +60,9 @@ class Query(graphene.ObjectType): two_factor = graphene.Field(TwoFactorType) + rooms = graphene.List(RoomType) + room_by_id = graphene.Field(RoomType, id=graphene.ID()) + def resolve_ping(root, info, payload) -> str: return payload @@ -157,6 +161,20 @@ class Query(graphene.ObjectType): return None return info.context.user + @staticmethod + def resolve_rooms(root, info, **kwargs): + return Room.objects.all() # FIXME permissions + + @staticmethod + def resolve_room_by_id(root, info, **kwargs): + pk = kwargs.get("id") + room_object = Room.objects.get(pk=pk) + + if not info.context.user.has_perm("core.view_room_rule"): + raise PermissionDenied + + return room_object + class Mutation(graphene.ObjectType): update_person = PersonMutation.Field() @@ -165,6 +183,9 @@ class Mutation(graphene.ObjectType): celery_progress_fetched = CeleryProgressFetchedMutation.Field() + create_room = RoomCreateMutation.Field() + update_rooms = RoomBatchPatchMutation.Field() + def build_global_schema(): """Build global GraphQL schema from all apps.""" diff --git a/aleksis/core/schema/base.py b/aleksis/core/schema/base.py index e927dadccaaab7b2bf39c2110286970222f70f5b..f100f562beb3d3185059f38fa47f8a2c4d463760 100644 --- a/aleksis/core/schema/base.py +++ b/aleksis/core/schema/base.py @@ -1,6 +1,9 @@ import graphene from graphene_django import DjangoObjectType +from django.db.models import Model +from django.contrib.contenttypes.models import ContentType + from ..util.core_helpers import queryset_rules_filter @@ -24,3 +27,41 @@ class FieldFileType(graphene.ObjectType): def resolve_absolute_url(root, info, **kwargs): return info.context.build_absolute_uri(root.url) if root else "" + + +class PermissionsTypeMixin: + """Mixin for adding permissions to a Graphene type. + + To configure the names for the permissions or to do + different permission checking, override the respective + methods `resolve_can_edit` and `resolve_can_delete` + """ + + can_edit = graphene.Boolean() + can_delete = graphene.Boolean() + + @staticmethod + def resolve_can_edit(root: Model, info, **kwargs): + content_type = ContentType.objects.get_for_model(root) + perm = f"{content_type.app_label}.edit_{content_type.model}_rule" + return info.context.user.has_perm(perm, root) + + @staticmethod + def resolve_can_delete(root: Model, info, **kwargs): + content_type = ContentType.objects.get_for_model(root) + perm = f"{content_type.app_label}.delete_{content_type.model}_rule" + return info.context.user.has_perm(perm, root) + + +class PermissionBatchPatchMixin: + class Meta: + login_required = True + + @classmethod + def check_permissions(cls, root, info, input): + # TODO: Check PERMISSIONS (or rules) + return True + + + + diff --git a/aleksis/core/schema/room.py b/aleksis/core/schema/room.py index d4f76700793d2f7eededaac1b0361ebeff1a6a5a..d4d5c1480fad01f20f4fc61bd0bcc4a35957536a 100644 --- a/aleksis/core/schema/room.py +++ b/aleksis/core/schema/room.py @@ -1,9 +1,23 @@ from graphene_django import DjangoObjectType +from graphene_django_cud.mutations import DjangoCreateMutation, DjangoBatchPatchMutation +from .base import PermissionsTypeMixin, PermissionBatchPatchMixin from ..models import Room -class RoomType(DjangoObjectType): +class RoomType(PermissionsTypeMixin, DjangoObjectType): class Meta: model = Room fields = ("id", "name", "short_name") + + +class RoomCreateMutation(DjangoCreateMutation): + class Meta: + model = Room + permissions = "core.create_room" + + +class RoomBatchPatchMutation(PermissionBatchPatchMixin, DjangoBatchPatchMutation): + class Meta: + model = Room + permissions = "core.change_room" diff --git a/pyproject.toml b/pyproject.toml index 9a3318eaef990a7445fd14bcbabad0885b1ac6b2..3c2d76502766827da5c2a90a936ffd5645f9fc88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,6 +127,7 @@ customidenticon = "^0.1.5" graphene-django = "^3.0.0" selenium = "^4.4.3" django-vite = "^2.0.2" +graphene-django-cud = "^0.10.0" [tool.poetry.extras] ldap = ["django-auth-ldap"]