from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.shortcuts import redirect from django.urls import reverse from django.views.generic import CreateView, DetailView, ListView, UpdateView from .forms import ProjectBriefForm, WIZARD_STEPS from .models import ProjectBrief, ProjectBriefAttachment class ClientBriefMixin(LoginRequiredMixin): def get_queryset(self): return ProjectBrief.objects.filter(client=self.request.user) class DashboardView(ClientBriefMixin, ListView): model = ProjectBrief template_name = "projects/dashboard.html" context_object_name = "briefs" paginate_by = 10 class ProjectBriefCreateView(LoginRequiredMixin, CreateView): model = ProjectBrief form_class = ProjectBriefForm template_name = "projects/brief_wizard.html" def get_success_url(self): messages.success(self.request, "Project brief submitted. We'll review it soon.") return reverse("projects:detail", kwargs={"pk": self.object.pk}) def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["form_title"] = "Submit a Project Brief" ctx["submit_label"] = "Submit brief" ctx["wizard_steps"] = WIZARD_STEPS ctx["initial_step"] = self._initial_step() return ctx def _initial_step(self): form = self.get_form() if form.is_bound and form.errors: return form.first_error_step() return 1 def get_form_kwargs(self): kwargs = super().get_form_kwargs() if self.request.method == "POST": kwargs["file_list"] = self.request.FILES.getlist("attachments") else: kwargs["file_list"] = None return kwargs def form_valid(self, form): self.object = form.save(commit=False) self.object.client = self.request.user self.object.save() self._save_attachments(form) return redirect(self.get_success_url()) def _save_attachments(self, form): for uploaded_file, original_name in form.cleaned_data.get("attachments", []): attachment = ProjectBriefAttachment( brief=self.object, original_filename=original_name, ) attachment.file.save(original_name, uploaded_file, save=True) class ProjectBriefDetailView(ClientBriefMixin, DetailView): model = ProjectBrief template_name = "projects/brief_detail.html" context_object_name = "brief" class ProjectBriefUpdateView(ClientBriefMixin, UserPassesTestMixin, UpdateView): model = ProjectBrief form_class = ProjectBriefForm template_name = "projects/brief_wizard.html" def test_func(self): brief = self.get_object() return brief.is_editable_by_client def handle_no_permission(self): messages.error(self.request, "This brief can no longer be edited.") return redirect("projects:detail", pk=self.kwargs["pk"]) def get_success_url(self): messages.success(self.request, "Project brief updated.") return reverse("projects:detail", kwargs={"pk": self.object.pk}) def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["form_title"] = "Edit Project Brief" ctx["submit_label"] = "Save changes" ctx["brief"] = self.object ctx["wizard_steps"] = WIZARD_STEPS ctx["initial_step"] = self._initial_step() return ctx def _initial_step(self): form = self.get_form() if form.is_bound and form.errors: return form.first_error_step() return 1 def get_form_kwargs(self): kwargs = super().get_form_kwargs() if self.request.method == "POST": kwargs["file_list"] = self.request.FILES.getlist("attachments") else: kwargs["file_list"] = None return kwargs def form_valid(self, form): response = super().form_valid(form) self._save_attachments(form) return response def _save_attachments(self, form): for uploaded_file, original_name in form.cleaned_data.get("attachments", []): attachment = ProjectBriefAttachment( brief=self.object, original_filename=original_name, ) attachment.file.save(original_name, uploaded_file, save=True)