From 2aa163e6edd6da467aeadfca573c0f7b9cffa071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Wed, 5 Jul 2017 19:40:35 +0200 Subject: [PATCH] start review and reject changesets --- src/c3nav/editor/forms.py | 12 ++++- src/c3nav/editor/models/changeset.py | 51 +++++++++++++++++++ .../editor/templates/editor/changeset.html | 12 ++++- ...tore_confirm.html => changeset_apply.html} | 0 .../templates/editor/changeset_reject.html | 20 ++++++++ src/c3nav/editor/views/changes.py | 37 +++++++++++++- 6 files changed, 128 insertions(+), 4 deletions(-) rename src/c3nav/editor/templates/editor/{changeset_restore_confirm.html => changeset_apply.html} (100%) create mode 100644 src/c3nav/editor/templates/editor/changeset_reject.html diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index 8e576500..e066fdc9 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -2,12 +2,12 @@ import json from collections import OrderedDict from django.conf import settings -from django.forms import CharField, ModelForm, ValidationError +from django.forms import BooleanField, CharField, ModelForm, ValidationError from django.forms.widgets import HiddenInput from django.utils.translation import ugettext_lazy as _ from shapely.geometry.geo import mapping -from c3nav.editor.models import ChangeSet +from c3nav.editor.models import ChangeSet, ChangeSetUpdate class MapitemFormMixin(ModelForm): @@ -112,3 +112,11 @@ class ChangeSetForm(ModelForm): class Meta: model = ChangeSet fields = ('title', 'description') + + +class RejectForm(ModelForm): + final = BooleanField(label=_('Final rejection'), required=False) + + class Meta: + model = ChangeSetUpdate + fields = ('comment', ) diff --git a/src/c3nav/editor/models/changeset.py b/src/c3nav/editor/models/changeset.py index 04614a48..14a63f47 100644 --- a/src/c3nav/editor/models/changeset.py +++ b/src/c3nav/editor/models/changeset.py @@ -297,6 +297,20 @@ class ChangeSet(models.Model): def can_unpropose(self, request): return self.author_id == request.user.pk and self.state in ('proposed', 'reproposed') + def can_review(self, request): + # todo implement permissions + return self.is_author(request) + + def can_start_review(self, request): + return self.can_review(request) and self.state in ('proposed', 'reproposed') + + def can_end_review(self, request): + return self.can_review(request) and self.state == 'review' and self.assigned_to == request.user + + def can_unreject(self, request): + return (self.can_review(request) and self.state in ('rejected', 'finallyrejected') and + self.assigned_to == request.user) + """ Update methods """ @@ -316,6 +330,43 @@ class ChangeSet(models.Model): self.last_state_update = update self.save() + def start_review(self, user): + assign_to = user + if self.assigned_to == user: + assign_to = None + else: + self.assigned_to = user + + if self.state != 'review': + update = self.updates.create(user=user, state='review', assigned_to=assign_to) + self.state = 'review' + self.last_state_update = update + elif assign_to is None: + return + else: + update = self.updates.create(user=user, assigned_to=assign_to) + + self.last_update = update + self.save() + + def reject(self, user, comment: str, final: bool): + state = 'finallyrejected' if final else 'rejected' + update = self.updates.create(user=user, state=state, comment=comment) + self.state = state + self.last_state_change = update + self.last_update = update + self.save() + + def unreject(self, user): + update = self.updates.create(user=user, state='review') + self.state = 'review' + self.last_state_change = update + self.last_update = update + self.save() + + def apply(self, user): + pass + def activate(self, request): request.session['changeset'] = self.pk diff --git a/src/c3nav/editor/templates/editor/changeset.html b/src/c3nav/editor/templates/editor/changeset.html index 93ab81e9..00be036e 100644 --- a/src/c3nav/editor/templates/editor/changeset.html +++ b/src/c3nav/editor/templates/editor/changeset.html @@ -127,9 +127,19 @@ {% if can_edit %} {% trans 'Edit' %} {% endif %} - {% if can_edit and not changeset.proposed and active %} + {% if can_edit and not changeset.proposed %} {% endif %} + {% if can_start_review %} + + {% endif %} + {% if can_end_review %} + + + {% endif %} + {% if can_unreject %} + + {% endif %} {% endif %} {% if not active and not changeset.closed %} diff --git a/src/c3nav/editor/templates/editor/changeset_restore_confirm.html b/src/c3nav/editor/templates/editor/changeset_apply.html similarity index 100% rename from src/c3nav/editor/templates/editor/changeset_restore_confirm.html rename to src/c3nav/editor/templates/editor/changeset_apply.html diff --git a/src/c3nav/editor/templates/editor/changeset_reject.html b/src/c3nav/editor/templates/editor/changeset_reject.html new file mode 100644 index 00000000..1c070d97 --- /dev/null +++ b/src/c3nav/editor/templates/editor/changeset_reject.html @@ -0,0 +1,20 @@ +{% load bootstrap3 %} +{% load i18n %} + +{% include 'editor/fragment_modal_close.html' %} +

{% trans 'Reject changes' %}

+
+ {% csrf_token %} +

{% trans 'Please explain why you reject these changes.' %}

+ {% bootstrap_form form %} + + {% buttons %} + + + {% trans 'Cancel' %} + + + {% endbuttons %} +
diff --git a/src/c3nav/editor/views/changes.py b/src/c3nav/editor/views/changes.py index cf87df77..cbd89eda 100644 --- a/src/c3nav/editor/views/changes.py +++ b/src/c3nav/editor/views/changes.py @@ -9,7 +9,7 @@ from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils.translation import ugettext_lazy as _ -from c3nav.editor.forms import ChangeSetForm +from c3nav.editor.forms import ChangeSetForm, RejectForm from c3nav.editor.models import ChangeSet from c3nav.editor.utils import is_created_pk from c3nav.editor.views.base import sidebar_view @@ -83,6 +83,38 @@ def changeset_detail(request, pk): return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) + elif request.POST.get('review') == '1': + with changeset.lock_to_edit() as changeset: + if changeset.can_start_review(request): + changeset.start_review(request.user) + messages.success(request, _('You are not reviewing these changes.')) + else: + messages.error(request, _('You cannot review these changes.')) + + return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) + + elif request.POST.get('reject') == '1': + with changeset.lock_to_edit() as changeset: + if not changeset.can_end_review(request): + messages.error(request, _('You cannot reject these changes.')) + return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) + + if request.POST.get('reject_confirm') == '1': + form = RejectForm(data=request.POST) + if form.is_valid(): + changeset.reject(request.user, form.cleaned_data['comment'], form.cleaned_data['final']) + messages.success(request, _('You rejected these changes.')) + return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) + else: + form = RejectForm() + + return render(request, 'editor/changeset_reject.html', { + 'changeset': changeset, + 'form': form, + }) + + return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) + elif request.POST.get('delete') == '1': if not changeset.can_delete(request): raise PermissionDenied @@ -263,6 +295,9 @@ def changeset_detail(request, pk): 'can_edit': can_edit, 'can_delete': can_delete, 'can_unpropose': changeset.can_unpropose(request), + 'can_start_review': changeset.can_start_review(request), + 'can_end_review': changeset.can_end_review(request), + 'can_unreject': changeset.can_unreject(request), 'active': active, 'changed_objects': changed_objects_data, }