Skip to content

Commit

Permalink
Set appropriate permissions for UserCollabPluginMetaList, UserFavorit…
Browse files Browse the repository at this point in the history
…ePluginMetaList, PluginMetaStar's and PluginMetaCollaborator's views
  • Loading branch information
jbernal0019 committed Sep 20, 2021
1 parent a492e68 commit 8f4fc98
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 90 deletions.
5 changes: 2 additions & 3 deletions store_backend/plugins/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ class PluginMetaFilter(FilterSet):
lookup_expr='gte')
max_creation_date = django_filters.IsoDateTimeFilter(field_name='creation_date',
lookup_expr='lte')
owner_username = django_filters.CharFilter(field_name='owner__username',
lookup_expr='exact')
name = django_filters.CharFilter(field_name='name', lookup_expr='icontains')
name_exact = django_filters.CharFilter(field_name='name', lookup_expr='exact')
title = django_filters.CharFilter(field_name='title', lookup_expr='icontains')
Expand Down Expand Up @@ -121,10 +119,11 @@ def __str__(self):

class PluginMetaStarFilter(FilterSet):
plugin_name = django_filters.CharFilter(field_name='meta__name', lookup_expr='exact')
username = django_filters.CharFilter(field_name='user__username', lookup_expr='exact')

class Meta:
model = PluginMetaStar
fields = ['id', 'plugin_name']
fields = ['id', 'plugin_name', 'username']


class PluginMetaCollaborator(models.Model):
Expand Down
58 changes: 22 additions & 36 deletions store_backend/plugins/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from .models import PluginMetaCollaborator


class IsMetaOwnerOrReadOnly(permissions.BasePermission):
class IsStarOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow the collaborators with owner role to modify/edit a
plugin meta. Read-only is allowed to all other users.
Custom permission to only allow write access to the owner of a plugin star.
Read-only is allowed to all other users.
"""

def has_object_permission(self, request, view, obj):
Expand All @@ -14,73 +14,59 @@ def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True

# Write permissions are only allowed to the owners.
if request.user.is_authenticated:
try:
collab = PluginMetaCollaborator.objects.get(meta=obj, user=request.user)
except PluginMetaCollaborator.DoesNotExist:
return False
return collab.role == 'O'
return False


class IsStarOwner(permissions.BasePermission):
"""
Custom permission to only allow access to the owner of a plugin star.
"""

def has_object_permission(self, request, view, obj):
# Access is only allowed to the owner.
# Write access is only allowed to the owner.
return request.user == obj.user


class IsMetaOwnerOrCollabReadOnly(permissions.BasePermission):
class IsMetaOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow write access to the owners of a plugin meta.
Read-only is allowed to all collaborators.
Custom permission to only allow the collaborators with owner role to write a
plugin meta. Read-only is allowed to all other users.
"""

def has_object_permission(self, request, view, obj):
# Read permissions are only allowed to the collaborators.
if request.method in permissions.SAFE_METHODS:
return True

# Write permissions are only allowed to the owners.
if request.user.is_authenticated:
try:
collab = PluginMetaCollaborator.objects.get(meta=obj, user=request.user)
except PluginMetaCollaborator.DoesNotExist:
return False
return request.method in permissions.SAFE_METHODS or collab.role == 'O'
return False # not even a collaborator
return collab.role == 'O'
return False


class IsObjMetaOwnerAndNotUserOrCollabReadOnly(permissions.BasePermission):
class IsObjMetaOwnerAndNotUserOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow the owners of an obj's meta to modify/edit and only
when the request user is not the owner of the obj. Read-only is allowed to all
collaborators.
Custom permission to only allow write access to the owners of an obj's meta and only
when the request user is not the owner of the obj. Read-only is allowed to all other
users.
"""

def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True

# Read permissions are only allowed to the collaborators.
if request.user.is_authenticated:
try:
collab = PluginMetaCollaborator.objects.get(meta=obj.meta,
user=request.user)
except PluginMetaCollaborator.DoesNotExist:
return False
if request.method in permissions.SAFE_METHODS:
return True
return False # not even a collaborator
return collab.role == 'O' and obj.user != request.user
return False


class IsObjMetaOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow the owners of an obj's meta to write it.
Custom permission to only allow write access to the owners of an obj's meta.
Read-only is allowed to all other users.
"""

def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True

Expand Down
2 changes: 1 addition & 1 deletion store_backend/plugins/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def test_plugin_meta_star_list_success_authenticated(self):
self.client.login(username=self.username, password=self.password)
response = self.client.get(self.create_read_url)
self.assertContains(response, self.plugin_name)
self.assertNotContains(response, 'testplugin')
self.assertContains(response, 'testplugin')

def test_plugin_meta_star_list_failure_unauthenticated(self):
response = self.client.get(self.create_read_url)
Expand Down
39 changes: 9 additions & 30 deletions store_backend/plugins/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
from .serializers import (PluginMetaSerializer, PluginMetaStarSerializer,
PluginMetaCollaboratorSerializer,
PluginSerializer, PluginParameterSerializer)
from .permissions import (IsStarOwner, IsMetaOwnerOrReadOnly, IsObjMetaOwnerOrReadOnly,
IsMetaOwnerOrCollabReadOnly,
IsObjMetaOwnerAndNotUserOrCollabReadOnly)
from .permissions import (IsStarOwnerOrReadOnly, IsMetaOwnerOrReadOnly,
IsObjMetaOwnerOrReadOnly, IsObjMetaOwnerAndNotUserOrReadOnly)


class PluginMetaList(generics.ListAPIView):
Expand Down Expand Up @@ -121,23 +120,13 @@ def get_plugins_queryset(self):

class PluginMetaStarList(generics.ListCreateAPIView):
"""
A view for the collection of plugins' stars.
A view for the collection of plugin metas' stars.
"""
http_method_names = ['get', 'post']
queryset = PluginMetaStar.objects.all()
serializer_class = PluginMetaStarSerializer
permission_classes = (permissions.IsAuthenticated,)

def get_queryset(self):
"""
Overriden to return a custom queryset that is only comprised by the plugin
meta stars created by the currently authenticated user.
"""
user = self.request.user
# if the user is chris then return all the plugin meta stars in the system
if user.username == 'chris':
return PluginMetaStar.objects.all()
return PluginMetaStar.objects.filter(user=user)

def perform_create(self, serializer):
"""
Overriden to associate a plugin and authenticated user with the plugin star.
Expand Down Expand Up @@ -176,17 +165,6 @@ class PluginMetaStarListQuerySearch(generics.ListAPIView):
permission_classes = (permissions.IsAuthenticated,)
filterset_class = PluginMetaStarFilter

def get_queryset(self):
"""
Overriden to return a custom queryset that is only comprised by the plugin
meta stars created by the currently authenticated user.
"""
user = self.request.user
# if the user is chris then return all the plugin meta stars in the system
if user.username == 'chris':
return PluginMetaStar.objects.all()
return PluginMetaStar.objects.filter(user=user)


class PluginMetaStarDetail(generics.RetrieveDestroyAPIView):
"""
Expand All @@ -195,17 +173,17 @@ class PluginMetaStarDetail(generics.RetrieveDestroyAPIView):
http_method_names = ['get', 'delete']
queryset = PluginMetaStar.objects.all()
serializer_class = PluginMetaStarSerializer
permission_classes = (IsStarOwner,)
permission_classes = (permissions.IsAuthenticated, IsStarOwnerOrReadOnly,)


class PluginMetaCollaboratorList(generics.ListCreateAPIView):
"""
A view for the collection of meta-specific plugin meta collaborator list.
A view for the collection of plugin meta-specific plugin meta collaborator list.
"""
http_method_names = ['get', 'post']
queryset = PluginMeta.objects.all()
serializer_class = PluginMetaCollaboratorSerializer
permission_classes = (IsMetaOwnerOrCollabReadOnly,)
permission_classes = (permissions.IsAuthenticated, IsMetaOwnerOrReadOnly,)

def get_plugin_meta_collaborators_queryset(self):
"""
Expand Down Expand Up @@ -246,7 +224,8 @@ class PluginMetaCollaboratorDetail(generics.RetrieveUpdateDestroyAPIView):
http_method_names = ['get', 'put', 'delete']
queryset = PluginMetaCollaborator.objects.all()
serializer_class = PluginMetaCollaboratorSerializer
permission_classes = (IsObjMetaOwnerAndNotUserOrCollabReadOnly,)
permission_classes = (permissions.IsAuthenticated,
IsObjMetaOwnerAndNotUserOrReadOnly,)

def retrieve(self, request, *args, **kwargs):
"""
Expand Down
15 changes: 5 additions & 10 deletions store_backend/users/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ def test_user_detail_failure_unauthenticated(self):
response = self.client.get(self.read_update_url)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_user_detail_failure_access_denied(self):
self.client.login(username=self.other_username, password=self.other_password)
response = self.client.get(self.read_update_url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_user_update_success(self):
self.client.login(username=self.username, password=self.password)
response = self.client.put(self.read_update_url, data=self.put,
Expand Down Expand Up @@ -146,11 +151,6 @@ def test_user_plugin_meta_collaborator_list_failure_unauthenticated(self):
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_user_plugin_meta_collaborator_list_failure_access_denied(self):
self.client.login(username=self.other_username, password=self.other_password)
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)


class UserFavoritePluginMetaListViewTests(UserViewTests):
"""
Expand Down Expand Up @@ -181,8 +181,3 @@ def test_user_favorite_plugin_meta_list_success_authenticated(self):
def test_user_favorite_plugin_meta_list_failure_unauthenticated(self):
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_user_favorite_plugin_meta_list_failure_access_denied(self):
self.client.login(username=self.other_username, password=self.other_password)
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
19 changes: 9 additions & 10 deletions store_backend/users/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@

from django.contrib.auth.models import User

from rest_framework import generics
from rest_framework import generics, permissions
from rest_framework.response import Response
from rest_framework.reverse import reverse

from collectionjson import services

from plugins.models import PluginMetaCollaborator
from plugins.serializers import PluginMetaSerializer, PluginMetaCollaboratorSerializer
from plugins.serializers import PluginMetaSerializer
from .serializers import UserSerializer
from .permissions import IsUser

Expand Down Expand Up @@ -65,26 +64,26 @@ class UserCollabPluginMetaList(generics.ListAPIView):
A view for the collection of user-specific plugin meta collaborators.
"""
queryset = User.objects.all()
serializer_class = PluginMetaCollaboratorSerializer
permission_classes = (IsUser,)
serializer_class = PluginMetaSerializer
permission_classes = (permissions.IsAuthenticated,)

def list(self, request, *args, **kwargs):
"""
Overriden to return the list of plugin meta collaborators for the queried user.
"""
queryset = self.get_user_collab_plugin_metas_queryset()
queryset = self.get_plugin_metas_queryset()
response = services.get_list_response(self, queryset)
user = self.get_object()
links = {'user': reverse('user-detail', request=request,
kwargs={"pk": user.id})}
return services.append_collection_links(response, links)

def get_user_collab_plugin_metas_queryset(self):
def get_plugin_metas_queryset(self):
"""
Custom method to get the actual plugin meta collaborators queryset.
Custom method to get the actual user-collaborated plugin metas queryset.
"""
user = self.get_object()
return PluginMetaCollaborator.objects.filter(user=user)
return self.filter_queryset(user.collab_plugin_metas.all())


class UserFavoritePluginMetaList(generics.ListAPIView):
Expand All @@ -93,7 +92,7 @@ class UserFavoritePluginMetaList(generics.ListAPIView):
"""
queryset = User.objects.all()
serializer_class = PluginMetaSerializer
permission_classes = (IsUser,)
permission_classes = (permissions.IsAuthenticated,)

def list(self, request, *args, **kwargs):
"""
Expand Down

0 comments on commit 8f4fc98

Please sign in to comment.