Skip to content
Snippets Groups Projects
Commit 71ef18a9 authored by Bastien Abadie's avatar Bastien Abadie
Browse files

Merge branch 'acl-admin' into 'master'

Remove corpora filtering for admins

See merge request !97
parents 4c157483 75ae3fec
No related branches found
No related tags found
1 merge request!97Remove corpora filtering for admins
from django.db.models import Sum
from django.http.response import Http404
from django.shortcuts import get_object_or_404
from django.core.exceptions import PermissionDenied
from django.conf import settings
......@@ -41,13 +42,13 @@ class DataImportsList(CorpusACLMixin, ListCreateAPIView):
if serializer.validated_data['mode'] not in (DataImportMode.Images, ):
raise ValidationError('Unsupported mode for now, sorry.')
if Right.Write not in serializer.validated_data['corpus'].get_acl_rights(self.request.user):
if not self.has_write_access(serializer.validated_data['corpus']):
raise PermissionDenied
return super().perform_create(serializer)
class DataImportDetails(RetrieveUpdateDestroyAPIView):
class DataImportDetails(CorpusACLMixin, RetrieveUpdateDestroyAPIView):
"""
Retrieve and edit a data import
"""
......@@ -60,7 +61,7 @@ class DataImportDetails(RetrieveUpdateDestroyAPIView):
def perform_update(self, serializer):
dataimport = serializer.instance
if Right.Write not in dataimport.corpus.get_acl_rights(self.request.user):
if not self.has_write_access(dataimport.corpus):
raise PermissionDenied
if dataimport.state not in (DataImportState.Created, DataImportState.Configured):
......@@ -84,7 +85,7 @@ class DataImportDetails(RetrieveUpdateDestroyAPIView):
dataimport.save()
def perform_destroy(self, instance):
if Right.Write not in instance.corpus.get_acl_rights(self.request.user):
if not self.has_write_access(instance.corpus):
raise PermissionDenied
if instance.state == DataImportState.Running:
raise ValidationError("Cannot delete a workflow while it is running")
......@@ -106,7 +107,7 @@ class DataImportFailures(ListAPIView):
).prefetch_related('dataimport__revision__repo', 'element').order_by('path', 'line')
class DataImportDemo(CreateAPIView):
class DataImportDemo(CorpusACLMixin, CreateAPIView):
"""
Create, configure and start an Images workflow from a single DataFile
"""
......@@ -117,7 +118,7 @@ class DataImportDemo(CreateAPIView):
def create(self, request, pk=None, **kwargs):
# Get Datafile
corpora = Corpus.objects.readable(self.request.user).filter(corpus_right__can_write=True)
corpora = Corpus.objects.writable(self.request.user)
datafile = get_object_or_404(DataFile, corpus__in=corpora, id=pk)
# Get volume, defaults to demo one
......@@ -133,7 +134,7 @@ class DataImportDemo(CreateAPIView):
volume = get_object_or_404(Element, **filters)
assert Right.Write in volume.corpus.get_acl_rights(self.request.user), \
assert self.has_write_access(volume.corpus), \
'Corpus is not writable'
# Start the import
......@@ -164,7 +165,7 @@ class DataFileList(CorpusACLMixin, ListAPIView):
return DataFile.objects.filter(corpus=self.get_corpus(self.kwargs['pk']))
class DataFileRetrieve(RetrieveUpdateDestroyAPIView):
class DataFileRetrieve(CorpusACLMixin, RetrieveUpdateDestroyAPIView):
"""
Get one file
"""
......@@ -175,17 +176,17 @@ class DataFileRetrieve(RetrieveUpdateDestroyAPIView):
return DataFile.objects.filter(corpus__in=Corpus.objects.readable(self.request.user))
def perform_update(self, serializer):
if Right.Write not in serializer.instance.corpus.get_acl_rights(self.request.user):
if not self.has_write_access(serializer.instance.corpus):
raise PermissionDenied
return super().perform_update(serializer)
def perform_destroy(self, instance):
if Right.Write not in instance.corpus.get_acl_rights(self.request.user):
if not self.has_write_access(instance.corpus):
raise PermissionDenied
return super().perform_destroy(instance)
class DataFileUpload(APIView):
class DataFileUpload(CorpusACLMixin, APIView):
"""
Upload a new file to a corpus
"""
......@@ -195,14 +196,10 @@ class DataFileUpload(APIView):
def post(self, request, pk=None, format=None):
if 'file' not in request.FILES:
raise ValidationError({'file': ['No file was sent in the request']})
corpus_qs = Corpus.objects.filter(id=pk)
if not corpus_qs.exists():
try:
corpus = self.get_corpus(pk, right=Right.Write)
except Http404:
raise ValidationError({'corpus': ['Corpus not found']})
corpus = corpus_qs.get()
# Check corpus is writable for current user
if Right.Write not in corpus.get_acl_rights(self.request.user):
raise PermissionDenied
file_obj = request.FILES['file']
......@@ -287,7 +284,7 @@ class AvailableRepositoriesList(ListCreateAPIView):
return Response(data={'import_id': str(dataimport.id)}, status=status.HTTP_201_CREATED)
class RepositoryRetrieve(RetrieveUpdateDestroyAPIView):
class RepositoryRetrieve(CorpusACLMixin, RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthenticated, )
serializer_class = RepositorySerializer
......@@ -298,12 +295,12 @@ class RepositoryRetrieve(RetrieveUpdateDestroyAPIView):
)
def perform_update(self, serializer):
if Right.Write not in serializer.instance.corpus.get_acl_rights(self.request.user):
if not self.has_write_access(serializer.instance.corpus):
raise PermissionDenied
return super().perform_update(self, serializer)
def perform_destroy(self, instance):
if Right.Write not in instance.corpus.get_acl_rights(self.request.user):
if not self.has_write_access(instance.corpus):
raise PermissionDenied
return super().perform_destroy(self, instance)
......@@ -314,7 +311,7 @@ class RepositoryStartImport(RetrieveAPIView):
def get_queryset(self):
return Repository.objects.filter(
credentials__user=self.request.user,
corpus__in=Corpus.objects.readable(self.request.user).filter(corpus_right__can_write=True),
corpus__in=Corpus.objects.writable(self.request.user),
)
def get(self, request, *args, **kwargs):
......
......@@ -253,7 +253,6 @@ class ExternalRepositorySerializer(serializers.BaseSerializer):
return {
'id': data['id'],
'corpus': Corpus.objects.readable(self.request.user)
.filter(corpus_right__can_write=True)
'corpus': Corpus.objects.writable(self.request.user)
.get(id=data['corpus'])
}
......@@ -140,3 +140,17 @@ class CorpusManager(models.Manager):
qs = qs.prefetch_related('corpus_right')
qs = qs.filter(models.Q(public=True) | models.Q(corpus_right__user=user))
return qs
def writable(self, user):
# An anonymous user cannot write anything
if user.is_anonymous:
return super().none()
qs = super().get_queryset().order_by('name')
# Admins have access to every corpus
if user.is_admin:
return qs.all()
# Authenticated users can write only on corpora with ACL
return qs.filter(corpus_right__user=user, corpus_right__can_write=True)
......@@ -43,7 +43,7 @@ class TranscriptionCreateSerializer(serializers.Serializer):
super().__init__(*args, **kwargs)
assert 'request' in self.context, 'An API request is required to initialize this serializer'
self.fields['element'].queryset = Element.objects.filter(
corpus__in=Corpus.objects.readable(self.context['request'].user).filter(corpus_right__can_write=True),
corpus__in=Corpus.objects.writable(self.context['request'].user),
)
......@@ -79,5 +79,5 @@ class TranscriptionsSerializer(serializers.Serializer):
super().__init__(*args, **kwargs)
assert 'request' in self.context, 'An API request is required to initialize this serializer'
self.fields['parent'].queryset = Element.objects.filter(
corpus__in=Corpus.objects.readable(self.context['request'].user).filter(corpus_right__can_write=True),
corpus__in=Corpus.objects.writable(self.context['request'].user),
)
......@@ -10,3 +10,17 @@ class CorpusACLMixin(object):
if right not in corpus.get_acl_rights(self.request.user):
raise PermissionDenied()
return corpus
def has_read_access(self, corpus):
assert isinstance(corpus, Corpus)
return corpus.public or self.request.user.is_admin or Right.Read in corpus.get_acl_rights(self.request.user)
def has_write_access(self, corpus):
assert isinstance(corpus, Corpus)
return self.request.user.is_admin or not self.request.user.is_anonymous and \
Right.Write in corpus.get_acl_rights(self.request.user)
def has_admin_access(self, corpus):
assert isinstance(corpus, Corpus)
return self.request.user.is_admin or not self.request.user.is_anonymous and \
Right.Admin in corpus.get_acl_rights(self.request.user)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment