import base64 from typing import Any, Dict, List # noqa from django.contrib.staticfiles import finders from django.core.exceptions import ImproperlyConfigured from django.http import HttpResponse from django.views.decorators.csrf import ensure_csrf_cookie from django.views.generic.base import View from rest_framework.response import Response from rest_framework.views import APIView as _APIView class CSRFMixin: """ Adds the csrf cookie to the response. """ @classmethod def as_view(cls, *args: Any, **kwargs: Any) -> View: view = super().as_view(*args, **kwargs) # type: ignore return ensure_csrf_cookie(view) class APIView(_APIView): """ The Django Rest framework APIView with improvements for OpenSlides. """ http_method_names = [] # type: List[str] """ The allowed actions have to be explicitly defined. Django allowes the following: http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] """ def get_context_data(self, **context: Any) -> Dict[str, Any]: """ Returns the context for the response. """ return context def method_call(self, request: Any, *args: Any, **kwargs: Any) -> Any: """ Http method that returns the response object with the context data. """ return Response(self.get_context_data()) # Add the http-methods and delete the method "method_call" get = post = put = patch = delete = head = options = trace = method_call del method_call class TemplateView(View): """ A view to serve a single cached template file. Subclasses have to provide 'template_name'. The state dict is used to cache the template. The state variable is static, but the object ID is not allowed to change. So the State has to be saved in this dict. Search for 'Borg design pattern' for more information. """ template_name = None # type: str state = {} # type: Dict[str, str] def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) if self.template_name is None: raise ImproperlyConfigured("'template_name' is not provided.") if self.template_name not in self.state: self.state[self.template_name] = self.load_template() def load_template(self) -> str: with open(finders.find(self.template_name)) as template: return template.read() def get(self, *args: Any, **kwargs: Any) -> HttpResponse: return HttpResponse(self.state[self.template_name]) class BinaryTemplateView(TemplateView): """ Loads the specified binary template and encode it with base64. """ def load_template(self) -> str: with open(finders.find(self.template_name), 'rb') as template: return base64.b64encode(template.read()).decode()