mirror of
https://github.com/Steffo99/sophon.git
synced 2024-12-23 07:14:21 +00:00
✨ Properly check permissions for Projects
This commit is contained in:
parent
a7ae9f28f5
commit
95f4981dec
3 changed files with 45 additions and 23 deletions
|
@ -9,19 +9,6 @@ import json
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
|
|
||||||
class RelatedToProject(metaclass=abc.ABCMeta):
|
|
||||||
"""
|
|
||||||
A model which is related to :class:`.Project` in some way.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_project(self) -> "Project":
|
|
||||||
"""
|
|
||||||
:return: The project this object is related to.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class DataSource(models.Model):
|
class DataSource(models.Model):
|
||||||
"""
|
"""
|
||||||
A :class:`.DataSource` is a web service which provides access to statistical information sourced by multiple data
|
A :class:`.DataSource` is a web service which provides access to statistical information sourced by multiple data
|
||||||
|
@ -312,15 +299,12 @@ class DataFlow(models.Model):
|
||||||
return f"[{self.datasource}] {self.id}"
|
return f"[{self.datasource}] {self.id}"
|
||||||
|
|
||||||
|
|
||||||
class Project(models.Model, RelatedToProject):
|
class Project(models.Model):
|
||||||
"""
|
"""
|
||||||
A research :class:`.Project` is a work which may use zero or more :class:`.DataSource`\\ s to prove or disprove an
|
A research :class:`.Project` is a work which may use zero or more :class:`.DataSource`\\ s to prove or disprove an
|
||||||
hypothesis.
|
hypothesis.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_project(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
slug = models.SlugField(
|
slug = models.SlugField(
|
||||||
"Slug",
|
"Slug",
|
||||||
help_text="Unique alphanumeric string which identifies the project.",
|
help_text="Unique alphanumeric string which identifies the project.",
|
||||||
|
@ -349,6 +333,7 @@ class Project(models.Model, RelatedToProject):
|
||||||
("PRIVATE", "🔒 Private"),
|
("PRIVATE", "🔒 Private"),
|
||||||
],
|
],
|
||||||
default="INTERNAL",
|
default="INTERNAL",
|
||||||
|
max_length=16,
|
||||||
)
|
)
|
||||||
|
|
||||||
owner = models.ForeignKey(
|
owner = models.ForeignKey(
|
||||||
|
@ -371,5 +356,24 @@ class Project(models.Model, RelatedToProject):
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_contributors(self):
|
||||||
|
return {self.owner, *self.collaborators.values()}
|
||||||
|
|
||||||
|
def can_be_viewed_by(self, user):
|
||||||
|
if self.visibility == "PUBLIC":
|
||||||
|
return True
|
||||||
|
elif self.visibility == "INTERNAL":
|
||||||
|
return not user.is_anonymous()
|
||||||
|
elif self.visibility == "PRIVATE":
|
||||||
|
return user in self.get_contributors()
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown visibility value: {self.visibility}")
|
||||||
|
|
||||||
|
def can_be_edited_by(self, user):
|
||||||
|
return user in self.get_contributors()
|
||||||
|
|
||||||
|
def can_be_administrated_by(self, user):
|
||||||
|
return user == self.owner
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.slug
|
return self.slug
|
||||||
|
|
18
sophon/core/permissions.py
Normal file
18
sophon/core/permissions.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import logging
|
||||||
|
from rest_framework import permissions
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectPermissions(permissions.BasePermission):
|
||||||
|
def has_object_permission(self, request, view, obj):
|
||||||
|
if view.action == "retrieve":
|
||||||
|
return obj.can_be_viewed_by(request.user)
|
||||||
|
elif view.action == "update":
|
||||||
|
return obj.can_be_edited_by(request.user)
|
||||||
|
elif view.action == "partial_update":
|
||||||
|
return obj.can_be_edited_by(request.user)
|
||||||
|
elif view.action == "destroy":
|
||||||
|
return obj.can_be_administrated_by(request.user)
|
||||||
|
log.warning(f"Rejecting permissions for unknown action: {view.action}")
|
||||||
|
return False
|
|
@ -1,5 +1,5 @@
|
||||||
from rest_framework import viewsets, decorators, response
|
from rest_framework import viewsets, decorators, response, permissions
|
||||||
from . import models, serializers
|
from . import models, serializers, permissions as custom_permissions
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class ProjectViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = models.Project.objects.all()
|
queryset = models.Project.objects.all()
|
||||||
serializer_class = serializers.ProjectSerializer
|
serializer_class = serializers.ProjectSerializer
|
||||||
permission_classes = []
|
permission_classes = [custom_permissions.ProjectPermissions]
|
||||||
|
|
||||||
|
|
||||||
class DataFlowViewSet(viewsets.ModelViewSet):
|
class DataFlowViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -21,7 +21,7 @@ class DataFlowViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = models.DataFlow.objects.all()
|
queryset = models.DataFlow.objects.all()
|
||||||
serializer_class = serializers.DataFlowSerializer
|
serializer_class = serializers.DataFlowSerializer
|
||||||
permission_classes = []
|
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
|
||||||
|
|
||||||
|
|
||||||
class DataSourceViewSet(viewsets.ModelViewSet):
|
class DataSourceViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -30,10 +30,10 @@ class DataSourceViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = models.DataSource.objects.all()
|
queryset = models.DataSource.objects.all()
|
||||||
serializer_class = serializers.DataSourceSerializer
|
serializer_class = serializers.DataSourceSerializer
|
||||||
permission_classes = []
|
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
|
||||||
|
|
||||||
@decorators.action(methods=["post"], detail=True)
|
@decorators.action(methods=["post"], detail=True)
|
||||||
def sync(self, request, pk):
|
def sync(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Syncronize the :class:`.models.DataFlow`\\ s with the ones stored in the server of the
|
Syncronize the :class:`.models.DataFlow`\\ s with the ones stored in the server of the
|
||||||
:class:`.models.DataSource`\\ .
|
:class:`.models.DataSource`\\ .
|
||||||
|
|
Loading…
Reference in a new issue