import json import logging from dal import autocomplete from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import UserPassesTestMixin from django.core.mail import send_mail from django.db.models import Q from django.http import HttpResponse from django.shortcuts import get_object_or_404 from django.urls import reverse from django.urls import reverse_lazy from django.utils.translation import get_language from django.views import View from django.views.generic import DetailView from django.views.generic.base import TemplateView from django.views.generic.edit import CreateView from django.views.generic.edit import UpdateView from . import forms from . import models from apps.files.models import File logger = logging.getLogger(__name__) NOTIFY_MESSAGE = """ Hello, Someone has submitted a new case study to the Ojuso website. Please follow the below link to look over and approve it: %s%s – Case Study Robot """ class Map(TemplateView): template_name = "map/index.html" class CreateCaseStudySelector(LoginRequiredMixin, TemplateView): template_name = "map/form-selector.html" class CreatePointOfInterest(LoginRequiredMixin, CreateView): """View for base case study form.""" template_name = "map/form-poi.html" success_url = "/case-study/create/success/" model = models.PointOfInterest form_class = forms.PointOfInterest def send_email(study_id): """Sends email to moderator to approve case study.""" try: send_mail( "New case study submitted", NOTIFY_MESSAGE % ( settings.SITE_URL, reverse("admin:map_casestudy_change", args=[study_id]), ), "noreply@ojuso.org", [settings.DATABASE_EMAIL], fail_silently=False, ) except Exception: logging.exception("Sending mail failed") # XXX This is bad. We should do something more useful with the error # than this. def delete_user_draft(user_id): """ Delete the draft of a given user """ try: draft = models.CaseStudyDraft.objects.get(author=user_id) draft.delete() except models.CaseStudyDraft.DoesNotExist: pass class FilesHandlerMixin: def remove_bad_fields(self, form): form.cleaned_data.pop("official_project_documents", None) form.cleaned_data.pop("other_documents", None) form.cleaned_data.pop("shapefiles", None) form.cleaned_data.pop("images", None) def add_file_refs(self, form): self.object.official_project_documents.set( form.cleaned_data.get("official_project_documents_files", []) ) self.object.other_documents.set( form.cleaned_data.get("other_documents_files", []) ) self.object.shapefiles.set(form.cleaned_data.get("shapefiles_files", [])) self.object.images.set(form.cleaned_data.get("images_files", [])) def handle_files(self, form): self.remove_bad_fields(form) self.object = form.save() self.add_file_refs(form) self.object.save() class BaseCreateForm(LoginRequiredMixin, FilesHandlerMixin, CreateView): """View for base case study form.""" template_name = "map/form-case_study.html" success_url = reverse_lazy("form-success") model = models.CaseStudy def form_valid(self, form): self.handle_files(form) self.object.author = self.request.user self.object.language = get_language() self.object.form_type = self.form_type self.object.save() send_email(self.object.id) delete_user_draft(self.request.user) return super().form_valid(form) class CreateShortCaseStudy(BaseCreateForm): """View for short version of case study form.""" form_class = forms.ShortCaseStudyForm form_type = "short" class CreateLongCaseStudy(BaseCreateForm): """View for long version of case study form.""" form_class = forms.LongCaseStudyForm form_type = "long" class CreateCaseStudySuccess(TemplateView): template_name = "map/form-success.html" class ViewCaseStudyDetail(DetailView): template_name = "map/detail.html" model = models.CaseStudy context_object_name = "case_study" class BaseEditForm(LoginRequiredMixin, FilesHandlerMixin, UpdateView): """View for base case study form.""" template_name = "map/form-case_study.html" success_url = reverse_lazy("form-success") model = models.CaseStudy def form_valid(self, form): self.handle_files(form) return super().form_valid(form) class EditCaseStudy(UserPassesTestMixin, BaseEditForm): form_class = forms.ShortCaseStudyForm def test_func(self): if settings.FFCAN_EDIT is False: return False object = self.get_object() if object.author: author = object.author.id else: author = -1 return self.request.user.is_authenticated and (author is self.request.user.id) class SpatialRefSysAutocomplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = models.SpatialRefSys.objects.all() if self.q: qs = qs.filter( Q(auth_name__icontains=self.q) | Q(auth_srid__icontains=self.q) ) return qs class DraftsAPI(LoginRequiredMixin, View): """ Retrieve or save a draft. XXX This should be refactored to use csrf protection. """ def get(self, request): draft = get_object_or_404(models.CaseStudyDraft, author=request.user) return HttpResponse(draft.data, content_type="application/json") def put(self, request): try: draft = models.CaseStudyDraft.objects.get(author=request.user) draft.data = request.body.decode() draft.save() return HttpResponse(status=200) # OK except models.CaseStudyDraft.DoesNotExist: # If it doesn't exist, create it models.CaseStudyDraft.objects.create( author=request.user, data=request.body.decode() ) return HttpResponse(status=201) # Created def delete(self, request): draft = get_object_or_404(models.CaseStudyDraft, author=request.user) data = json.loads(draft.data) for k in [ "official_project_documents", "other_documents", "shapefiles", "images", ]: try: keyname = k + "_files" field = data["data"]["form"][keyname] # Ignore empty fields if field["value"] == "": continue file_list = json.loads(field["value"]) # Delete those items for item in file_list: try: f = File.objects.get(id=item["id"]) if f.user != self.request.user: continue f.delete() except File.DoesNotExist: continue except Exception: # XXX What are we guarding against here? continue draft.delete() return HttpResponse(status=204)