diff --git a/froide_govplan/forms.py b/froide_govplan/forms.py index dc6e8a3..8854cce 100644 --- a/froide_govplan/forms.py +++ b/froide_govplan/forms.py @@ -1,11 +1,13 @@ from django import forms +from django.utils import timezone from django.utils.safestring import mark_safe +from django.utils.translation import gettext_lazy as _ import bleach from bleach.linkifier import Linker from tinymce.widgets import TinyMCE -from .models import GovernmentPlan, GovernmentPlanUpdate +from .models import GovernmentPlan, GovernmentPlanUpdate, PlanRating, PlanStatus BLEACH_OPTIONS = { "tags": [ @@ -47,7 +49,9 @@ class BleachField(forms.CharField): class GovernmentPlanForm(forms.ModelForm): - description = BleachField(required=False, widget=TinyMCE(attrs={"cols": 80, "rows": 30})) + description = BleachField( + required=False, widget=TinyMCE(attrs={"cols": 80, "rows": 30}) + ) class Meta: model = GovernmentPlan @@ -55,8 +59,74 @@ class GovernmentPlanForm(forms.ModelForm): class GovernmentPlanUpdateForm(forms.ModelForm): - content = BleachField(required=False, widget=TinyMCE(attrs={"cols": 80, "rows": 30})) + content = BleachField( + required=False, widget=TinyMCE(attrs={"cols": 80, "rows": 30}) + ) class Meta: model = GovernmentPlanUpdate fields = "__all__" + + +class GovernmentPlanUpdateProposalForm(forms.ModelForm): + title = forms.CharField( + label=_("title"), + help_text=_("Summarize the update in a title."), + widget=forms.TextInput( + attrs={ + "class": "form-control", + } + ), + ) + content = forms.CharField( + required=False, + label=_("details"), + help_text=_("Optionally give more details."), + widget=forms.Textarea(attrs={"class": "form-control", "rows": "3"}), + ) + url = forms.URLField( + label=_("source URL"), + help_text=_("Please give provide a link."), + widget=forms.URLInput( + attrs={"class": "form-control", "placeholder": "https://"} + ), + ) + status = forms.ChoiceField( + label=_("status"), + help_text=_("Has the status of the plan changed?"), + choices=[("", "---")] + PlanStatus.choices, + required=False, + ) + rating = forms.ChoiceField( + label=_("rating"), + help_text=_("What's your rating of the current implementation?"), + choices=[("", "---")] + PlanRating.choices, + required=False, + ) + + class Meta: + model = GovernmentPlanUpdate + fields = ( + "title", + "content", + "url", + "status", + "rating", + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def save(self, plan, user): + """ + This doesn't save instance, but saves + the change proposal. + """ + data = self.cleaned_data + plan.proposals = plan.proposals or {} + plan.proposals[user.id] = { + "data": data, + "timestamp": timezone.now().isoformat(), + } + plan.save() + return plan diff --git a/froide_govplan/templates/froide_govplan/detail.html b/froide_govplan/templates/froide_govplan/detail.html index 8eb064a..ed84cdf 100644 --- a/froide_govplan/templates/froide_govplan/detail.html +++ b/froide_govplan/templates/froide_govplan/detail.html @@ -6,6 +6,8 @@ {% load follow_tags %} {% load govplan %} {% load fds_ogimage %} +{% load form_helper %} +{% load content_helper %} {% block title %}{{ object.title }}{% endblock %} @@ -190,6 +192,51 @@ {% endfor %} +
+
+
+
+

Neue Entwicklung melden

+
+
+ {% if request.user.is_authenticated %} + + + {% else %} + + Bitte einloggen, um eine Entwicklung zu melden + + {% endif %} +
+
+
+
+ + {% endblock %} diff --git a/froide_govplan/urls.py b/froide_govplan/urls.py index 76d6ae0..163e426 100644 --- a/froide_govplan/urls.py +++ b/froide_govplan/urls.py @@ -4,6 +4,7 @@ from django.utils.translation import pgettext_lazy from .views import ( GovPlanDetailOGView, GovPlanDetailView, + GovPlanProposeUpdateView, GovPlanSectionDetailView, search, ) @@ -22,6 +23,11 @@ urlpatterns = [ GovPlanDetailOGView.as_view(), name="plan_og", ), + path( + pgettext_lazy("url part", "/plan//propose-update/"), + GovPlanProposeUpdateView.as_view(), + name="propose_planupdate", + ), path( pgettext_lazy("url part", "//"), GovPlanSectionDetailView.as_view(), diff --git a/froide_govplan/views.py b/froide_govplan/views.py index 4e6d213..5da4915 100644 --- a/froide_govplan/views.py +++ b/froide_govplan/views.py @@ -1,13 +1,17 @@ -from django.shortcuts import get_object_or_404, render -from django.views.generic import DetailView +from django.contrib import messages +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect, render +from django.utils.translation import gettext_lazy as _ +from django.views.generic import DetailView, UpdateView +from .forms import GovernmentPlanUpdateProposalForm from .models import Government, GovernmentPlan, GovernmentPlanSection class GovernmentMixin: - def get(self, *args, **kwargs): + def dispatch(self, *args, **kwargs): self.get_government() - return super().get(*args, **kwargs) + return super().dispatch(*args, **kwargs) def get_government(self): filter_kwarg = {} @@ -54,6 +58,8 @@ class GovPlanDetailView(GovernmentMixin, DetailView): "-timestamp" ) context["section"] = self.get_section() + if self.request.user.is_authenticated: + context["update_proposal_form"] = GovernmentPlanUpdateProposalForm() # For CMS toolbar self.request.govplan = self.object return context @@ -63,6 +69,32 @@ class GovPlanDetailOGView(GovPlanDetailView): template_name = "froide_govplan/plan_og.html" +class GovPlanProposeUpdateView(GovernmentMixin, LoginRequiredMixin, UpdateView): + template_name = "publicbody/add_proposal.html" + slug_url_kwarg = "plan" + form_class = GovernmentPlanUpdateProposalForm + + def get_queryset(self): + qs = GovernmentPlan.objects.filter(government=self.government) + if self.request.user.is_authenticated and self.request.user.is_staff: + return qs + return qs.filter(public=True) + + def get_success_url(self): + return self.object.get_absolute_url() + + def form_valid(self, form): + form.save(self.object, self.request.user) + messages.add_message( + self.request, + messages.INFO, + _( + "Thank you for your proposal. We will send you an email when it has been approved." + ), + ) + return redirect(self.object) + + def search(request): plans = GovernmentPlan.objects.search(request.GET.get("q", ""))