dd4754d045
Before this commit, there where two different locks when updating the restricted data cache. A future lock, what is faster but only works in the same thread. The other lock is in redis, it is not so fast, but also works in many threads. The future lock was buggy, because on a second call of update_restricted_data the same future was reused. So on the second run, the future was already done. I don't see any way to delete. The last client would have to delete it, but there is no way to find out which client the last one is.
105 lines
4.0 KiB
Python
105 lines
4.0 KiB
Python
from django.http import HttpResponseForbidden, HttpResponseNotFound
|
|
from django.views.static import serve
|
|
|
|
from .access_permissions import MediafileAccessPermissions
|
|
from .models import Mediafile
|
|
from ..core.config import config
|
|
from ..utils.auth import has_perm
|
|
from ..utils.rest_api import ModelViewSet, ValidationError
|
|
|
|
|
|
# Viewsets for the REST API
|
|
|
|
|
|
class MediafileViewSet(ModelViewSet):
|
|
"""
|
|
API endpoint for mediafile objects.
|
|
|
|
There are the following views: metadata, list, retrieve, create,
|
|
partial_update, update and destroy.
|
|
"""
|
|
|
|
access_permissions = MediafileAccessPermissions()
|
|
queryset = Mediafile.objects.all()
|
|
|
|
def check_view_permissions(self):
|
|
"""
|
|
Returns True if the user has required permissions.
|
|
"""
|
|
if self.action in ("list", "retrieve"):
|
|
result = self.get_access_permissions().check_permissions(self.request.user)
|
|
elif self.action == "metadata":
|
|
result = has_perm(self.request.user, "mediafiles.can_see")
|
|
elif self.action == "create":
|
|
result = has_perm(self.request.user, "mediafiles.can_see") and has_perm(
|
|
self.request.user, "mediafiles.can_upload"
|
|
)
|
|
elif self.action in ("partial_update", "update"):
|
|
result = (
|
|
has_perm(self.request.user, "mediafiles.can_see")
|
|
and has_perm(self.request.user, "mediafiles.can_upload")
|
|
and has_perm(self.request.user, "mediafiles.can_manage")
|
|
)
|
|
elif self.action == "destroy":
|
|
result = has_perm(self.request.user, "mediafiles.can_see") and has_perm(
|
|
self.request.user, "mediafiles.can_manage"
|
|
)
|
|
else:
|
|
result = False
|
|
return result
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
"""
|
|
Customized view endpoint to upload a new file.
|
|
"""
|
|
# Check permission to check if the uploader has to be changed.
|
|
uploader_id = self.request.data.get("uploader_id")
|
|
if (
|
|
uploader_id
|
|
and not has_perm(request.user, "mediafiles.can_manage")
|
|
and str(self.request.user.pk) != str(uploader_id)
|
|
):
|
|
self.permission_denied(request)
|
|
if not self.request.data.get("mediafile"):
|
|
raise ValidationError({"detail": "You forgot to provide a file."})
|
|
return super().create(request, *args, **kwargs)
|
|
|
|
def destroy(self, request, *args, **kwargs):
|
|
"""
|
|
Customized view endpoint to delete uploaded files.
|
|
|
|
Does also delete the file from filesystem.
|
|
"""
|
|
# To avoid Django calling save() and triggering autoupdate we do not
|
|
# use the builtin method mediafile.mediafile.delete() but call
|
|
# mediafile.mediafile.storage.delete(...) directly. This may have
|
|
# unattended side effects so be careful especially when accessing files
|
|
# on server via Django methods (file, open(), save(), ...).
|
|
mediafile = self.get_object()
|
|
mediafile.mediafile.storage.delete(mediafile.mediafile.name)
|
|
for logo in config["logos_available"]:
|
|
if config[logo]["path"] == mediafile.mediafile.url:
|
|
config[logo] = {
|
|
"display_name": config[logo]["display_name"],
|
|
"path": "",
|
|
}
|
|
return super().destroy(request, *args, **kwargs)
|
|
|
|
|
|
def protected_serve(request, path, document_root=None, show_indexes=False):
|
|
try:
|
|
mediafile = Mediafile.objects.get(mediafile=path)
|
|
except Mediafile.DoesNotExist:
|
|
return HttpResponseNotFound(content="Not found.")
|
|
|
|
can_see = has_perm(request.user, "mediafiles.can_see")
|
|
is_special_file = mediafile.is_logo() or mediafile.is_font()
|
|
is_hidden_but_no_perms = mediafile.hidden and not has_perm(
|
|
request.user, "mediafiles.can_see_hidden"
|
|
)
|
|
|
|
if not is_special_file and (not can_see or is_hidden_but_no_perms):
|
|
return HttpResponseForbidden(content="Forbidden.")
|
|
else:
|
|
return serve(request, path, document_root, show_indexes)
|