Use better introspection, no longer required "role_required"

This commit is contained in:
Oliver Walters 2021-02-26 21:36:40 +11:00
parent 0f6cdd0037
commit 6e3cb326fb
3 changed files with 25 additions and 54 deletions

View File

@ -60,28 +60,12 @@ class RolePermission(permissions.BasePermission):
permission = rolemap[request.method]
role = getattr(view, 'role_required', None)
# Extract the model name associated with this request
model = view.serializer_class.Meta.model
if not role:
# Role not specified - allow access
return True
roles = []
# And the specific database table
table = model._meta.db_table
if type(role) is str:
roles = [role]
elif type(role) in [list, tuple]:
roles = role
else:
raise TypeError(f"'role_required' is of incorrect type ({type(role)}) for view {type(view).__name__}")
result = users.models.RuleSet.check_table_permission(user, table, permission)
for role in roles:
if role not in users.models.RuleSet.RULESET_NAMES:
raise ValueError(f"Role '{role}' is not a valid role")
if not users.models.check_user_role(user, role, permission):
return False
# All checks passed
return True
return result

View File

@ -48,8 +48,6 @@ class PartCategoryTree(TreeSerializer):
def get_items(self):
return PartCategory.objects.all().prefetch_related('parts', 'children')
role_required = 'part'
class CategoryList(generics.ListCreateAPIView):
""" API endpoint for accessing a list of PartCategory objects.
@ -106,16 +104,12 @@ class CategoryList(generics.ListCreateAPIView):
'description',
]
role_required = 'part'
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single PartCategory object """
serializer_class = part_serializers.CategorySerializer
queryset = PartCategory.objects.all()
role_required = 'part'
class CategoryParameters(generics.ListAPIView):
""" API endpoint for accessing a list of PartCategoryParameterTemplate objects.
@ -126,8 +120,6 @@ class CategoryParameters(generics.ListAPIView):
queryset = PartCategoryParameterTemplate.objects.all()
serializer_class = part_serializers.CategoryParameterTemplateSerializer
role_required = 'part'
def get_queryset(self):
"""
Custom filtering:
@ -172,8 +164,6 @@ class PartSalePriceList(generics.ListCreateAPIView):
queryset = PartSellPriceBreak.objects.all()
serializer_class = part_serializers.PartSalePriceSerializer
role_required = 'part'
filter_backends = [
DjangoFilterBackend
]
@ -191,8 +181,6 @@ class PartAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
queryset = PartAttachment.objects.all()
serializer_class = part_serializers.PartAttachmentSerializer
role_required = 'part'
filter_backends = [
DjangoFilterBackend,
]
@ -210,8 +198,6 @@ class PartTestTemplateList(generics.ListCreateAPIView):
queryset = PartTestTemplate.objects.all()
serializer_class = part_serializers.PartTestTemplateSerializer
role_required = 'part'
def filter_queryset(self, queryset):
"""
Filter the test list queryset.
@ -253,8 +239,6 @@ class PartThumbs(generics.ListAPIView):
API endpoint for retrieving information on available Part thumbnails
"""
role_required = 'part'
queryset = Part.objects.all()
serializer_class = part_serializers.PartThumbSerializer
@ -291,8 +275,6 @@ class PartThumbsUpdate(generics.RetrieveUpdateAPIView):
queryset = Part.objects.all()
serializer_class = part_serializers.PartThumbSerializerUpdate
role_required = 'part'
filter_backends = [
DjangoFilterBackend
]
@ -301,8 +283,6 @@ class PartThumbsUpdate(generics.RetrieveUpdateAPIView):
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single Part object """
role_required = 'part'
queryset = Part.objects.all()
serializer_class = part_serializers.PartSerializer
@ -389,8 +369,6 @@ class PartList(generics.ListCreateAPIView):
queryset = Part.objects.all()
role_required = 'part'
starred_parts = None
def get_serializer(self, *args, **kwargs):
@ -717,8 +695,6 @@ class PartParameterTemplateList(generics.ListCreateAPIView):
- POST: Create a new PartParameterTemplate object
"""
role_required = 'part'
queryset = PartParameterTemplate.objects.all()
serializer_class = part_serializers.PartParameterTemplateSerializer
@ -738,8 +714,6 @@ class PartParameterList(generics.ListCreateAPIView):
- POST: Create a new PartParameter object
"""
role_required = 'part'
queryset = PartParameter.objects.all()
serializer_class = part_serializers.PartParameterSerializer
@ -760,8 +734,6 @@ class BomList(generics.ListCreateAPIView):
- POST: Create a new BomItem object
"""
role_required = 'part'
serializer_class = part_serializers.BomItemSerializer
def list(self, request, *args, **kwargs):
@ -901,8 +873,6 @@ class BomList(generics.ListCreateAPIView):
class BomDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single BomItem object """
role_required = 'part'
queryset = BomItem.objects.all()
serializer_class = part_serializers.BomItemSerializer
@ -910,8 +880,6 @@ class BomDetail(generics.RetrieveUpdateDestroyAPIView):
class BomItemValidate(generics.UpdateAPIView):
""" API endpoint for validating a BomItem """
role_required = 'part'
# Very simple serializers
class BomItemValidationSerializer(serializers.Serializer):

View File

@ -166,6 +166,25 @@ class RuleSet(models.Model):
can_delete = models.BooleanField(verbose_name=_('Delete'), default=False, help_text=_('Permission to delete items'))
@classmethod
def check_table_permission(cls, user, table, permission):
"""
Check if the provided user has the specified permission against the table
"""
# If the table does *not* require permissions
if table in cls.RULESET_IGNORE:
return True
# Work out which roles touch the given table
for role in cls.RULESET_NAMES:
if table in cls.RULESET_MODELS[role]:
if check_user_role(user, role, permission):
return True
return False
@staticmethod
def get_model_permission_string(model, permission):
"""