OpenSlides/openslides/mediafiles/views.py
2019-02-19 21:45:41 +01:00

105 lines
4.0 KiB
Python

from django.http import HttpResponseForbidden, HttpResponseNotFound
from django.views.static import serve
from ..core.config import config
from ..utils.auth import has_perm
from ..utils.rest_api import ModelViewSet, ValidationError
from .access_permissions import MediafileAccessPermissions
from .models import Mediafile
# 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)