From b45347253977924e1f0244cb543b937160766b30 Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Sat, 10 Jun 2017 11:58:06 +0200
Subject: [PATCH] Add Update/Delete productionevent views

---
 production/managers.py                        |  5 +++
 production/models.py                          | 13 +++++-
 .../production/_production_events.html        | 15 ++++---
 .../production/_production_stream_card.html   |  2 +-
 .../templates/production/completed.html       |  4 +-
 .../templates/production/production.html      |  2 +
 .../productionevent_confirm_delete.html       | 40 +++++++++++++++++++
 .../production/productionevent_form.html      | 30 ++++++++++++++
 production/urls.py                            |  8 +++-
 production/views.py                           | 38 +++++++++++++++++-
 10 files changed, 146 insertions(+), 11 deletions(-)
 create mode 100644 production/templates/production/productionevent_confirm_delete.html
 create mode 100644 production/templates/production/productionevent_form.html

diff --git a/production/managers.py b/production/managers.py
index 4379df507..ca9b5d0ba 100644
--- a/production/managers.py
+++ b/production/managers.py
@@ -9,3 +9,8 @@ class ProductionStreamManager(models.Manager):
 
     def ongoing(self):
         return self.filter(status=PRODUCTION_STREAM_ONGOING)
+
+
+class ProductionEventManager(models.Manager):
+    def get_my_events(self, current_contributor):
+        return self.filter(noted_by=current_contributor)
diff --git a/production/models.py b/production/models.py
index f2ec3b93c..27e8c6a15 100644
--- a/production/models.py
+++ b/production/models.py
@@ -1,8 +1,9 @@
 from django.db import models
 from django.utils import timezone
+from django.core.urlresolvers import reverse
 
 from .constants import PRODUCTION_STREAM_STATUS, PRODUCTION_STREAM_ONGOING, PRODUCTION_EVENTS
-from .managers import ProductionStreamManager
+from .managers import ProductionStreamManager, ProductionEventManager
 
 from scipost.models import Contributor
 
@@ -23,6 +24,11 @@ class ProductionStream(models.Model):
     def __str__(self):
         return str(self.submission)
 
+    def get_absolute_url(self):
+        if self.status == PRODUCTION_STREAM_ONGOING:
+            return reverse('production:production') + '#stream_' + str(self.id)
+        return reverse('production:completed') + '#stream_' + str(self.id)
+
     def total_duration(self):
         totdur = self.productionevent_set.aggregate(models.Sum('duration'))
         return totdur['duration__sum']
@@ -36,5 +42,10 @@ class ProductionEvent(models.Model):
     noted_by = models.ForeignKey(Contributor, on_delete=models.CASCADE)
     duration = models.DurationField(blank=True, null=True)
 
+    objects = ProductionEventManager()
+
     def __str__(self):
         return '%s: %s' % (str(self.stream.submission), self.get_event_display())
+
+    def get_absolute_url(self):
+        return self.stream.get_absolute_url()
diff --git a/production/templates/production/_production_events.html b/production/templates/production/_production_events.html
index 5903e4768..e7d168b13 100644
--- a/production/templates/production/_production_events.html
+++ b/production/templates/production/_production_events.html
@@ -2,14 +2,19 @@
 
 <ul>
   {% for event in events %}
-        <li id="{{ event.id }}">
-          <div class="font-weight-bold">{{ event.get_event_display }} <small class="text-muted">noted {{ event.noted_on }} by {{ event.noted_by }}</small>
-          </div>
+        <li id="event_{{ event.id }}">
+          <p class="mb-0 font-weight-bold">{{ event.get_event_display }}
+              {% if event.noted_by == request.user.contributor %}
+                  &middot; <a href="{% url 'production:update_event' event.id %}">Edit</a>
+                  &middot; <a class="text-danger" href="{% url 'production:delete_event' event.id %}">Delete</a>
+              {% endif %}
+          </p>
+          <p class="text-muted mb-1">noted {{ event.noted_on }} by {{ event.noted_by }}</p>
           {% if event.duration %}
-          <div><small>Duration: {{ event.duration|duration }}</small></div>
+              <div class="mb-2">Duration: {{ event.duration|duration }}</div>
           {% endif %}
           {% if event.comments %}
-          <div>{{ event.comments|linebreaks }}</div>
+              <div>{{ event.comments|linebreaks }}</div>
           {% endif %}
         </li>
     {% empty %}
diff --git a/production/templates/production/_production_stream_card.html b/production/templates/production/_production_stream_card.html
index 138be8b93..fab873137 100644
--- a/production/templates/production/_production_stream_card.html
+++ b/production/templates/production/_production_stream_card.html
@@ -1,7 +1,7 @@
 {% load bootstrap %}
 {% load scipost_extras %}
 
-<div class="w-100">
+<div class="w-100" id="stream_{{stream.id}}">
     {% include 'submissions/_submission_card_content_sparse.html' with submission=stream.submission %}
 </div>
 <div class="card-block">
diff --git a/production/templates/production/completed.html b/production/templates/production/completed.html
index 0bb839176..ec8c987bf 100644
--- a/production/templates/production/completed.html
+++ b/production/templates/production/completed.html
@@ -5,6 +5,8 @@
     <span class="breadcrumb-item">Completed production streams</span>
 {% endblock %}
 
+{% block pagetitle %}: Completed production streams{% endblock pagetitle %}
+
 {% load bootstrap %}
 
 {% block content %}
@@ -19,7 +21,7 @@
     <ul class="list-group list-group-flush">
       {% for stream in streams %}
         <li class="list-group-item">
-            <div class="w-100">{% include 'submissions/_submission_card_content_sparse.html' with submission=stream.submission %}</div>
+            <div class="w-100" id="stream_{{stream.id}}">{% include 'submissions/_submission_card_content_sparse.html' with submission=stream.submission %}</div>
             <div class="card-block">
                 <h3>Events</h3>
                 {% include 'production/_production_events.html' with events=stream.productionevent_set.all %}
diff --git a/production/templates/production/production.html b/production/templates/production/production.html
index 21f992911..40f12bcc4 100644
--- a/production/templates/production/production.html
+++ b/production/templates/production/production.html
@@ -5,6 +5,8 @@
     <span class="breadcrumb-item">Production page</span>
 {% endblock %}
 
+{% block pagetitle %}: Production page{% endblock pagetitle %}
+
 {% load bootstrap %}
 
 {% block content %}
diff --git a/production/templates/production/productionevent_confirm_delete.html b/production/templates/production/productionevent_confirm_delete.html
new file mode 100644
index 000000000..d279e44da
--- /dev/null
+++ b/production/templates/production/productionevent_confirm_delete.html
@@ -0,0 +1,40 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <a href="{{object.get_absolute_url}}" class="breadcrumb-item">Production streams</a>
+    <span class="breadcrumb-item">Delete production event</span>
+{% endblock %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Delete production event</h1>
+        {% include 'submissions/_submission_card_content_sparse.html' with submission=object.stream.submission %}
+    </div>
+</div>
+<div class="row">
+  <div class="col-12">
+      <form method="post">
+        {% csrf_token %}
+            <h3 class="mb-2">Are you sure you want to delete this production event?</h3>
+            <div class="card card-outline-secondary">
+                <div class="card-block">
+                    <p class="mb-0 font-weight-bold">{{ object.get_event_display }}
+                    </p>
+                    <p class="text-muted mb-1">noted {{ object.noted_on }} by {{ object.noted_by }}</p>
+                    {% if object.comments %}
+                        <div>{{ object.comments|linebreaks }}</div>
+                    {% endif %}
+                </div>
+            </div>
+            <input type="submit" class="btn btn-danger" value="Yes, delete event" />
+      </form>
+    </ul>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/production/templates/production/productionevent_form.html b/production/templates/production/productionevent_form.html
new file mode 100644
index 000000000..fc90e04c9
--- /dev/null
+++ b/production/templates/production/productionevent_form.html
@@ -0,0 +1,30 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <a href="{{object.get_absolute_url}}" class="breadcrumb-item">Production streams</a>
+    <span class="breadcrumb-item">Edit production event</span>
+{% endblock %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Edit production event</h1>
+        {% include 'submissions/_submission_card_content_sparse.html' with submission=object.stream.submission %}
+    </div>
+</div>
+<div class="row">
+  <div class="col-12">
+      <form method="post">
+        {% csrf_token %}
+        {{ form|bootstrap }}
+        <input type="submit" class="btn btn-secondary" name="submit" value="Submit">
+      </form>
+    </ul>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/production/urls.py b/production/urls.py
index 3ff66bdb8..cc5bf527b 100644
--- a/production/urls.py
+++ b/production/urls.py
@@ -5,8 +5,12 @@ from production import views as production_views
 urlpatterns = [
     url(r'^$', production_views.production, name='production'),
     url(r'^completed$', production_views.completed, name='completed'),
-    url(r'^add_event/(?P<stream_id>[0-9]+)$',
+    url(r'^streams/(?P<stream_id>[0-9]+)/events/add$',
         production_views.add_event, name='add_event'),
-    url(r'^mark_as_completed/(?P<stream_id>[0-9]+)$',
+    url(r'^streams/(?P<stream_id>[0-9]+)/mark_completed$',
         production_views.mark_as_completed, name='mark_as_completed'),
+    url(r'^events/(?P<event_id>[0-9]+)/edit',
+        production_views.UpdateEventView.as_view(), name='update_event'),
+    url(r'^events/(?P<event_id>[0-9]+)/delete',
+        production_views.DeleteEventView.as_view(), name='delete_event'),
 ]
diff --git a/production/views.py b/production/views.py
index abbbe4470..0a7536f6a 100644
--- a/production/views.py
+++ b/production/views.py
@@ -2,11 +2,13 @@ from django.contrib import messages
 from django.core.urlresolvers import reverse
 from django.shortcuts import get_object_or_404, render, redirect
 from django.utils import timezone
+from django.utils.decorators import method_decorator
+from django.views.generic.edit import UpdateView, DeleteView
 
 from guardian.decorators import permission_required
 
 from .constants import PRODUCTION_STREAM_COMPLETED
-from .models import ProductionStream
+from .models import ProductionStream, ProductionEvent
 from .forms import ProductionEventForm
 
 
@@ -53,6 +55,40 @@ def add_event(request, stream_id):
     return redirect(reverse('production:production'))
 
 
+@method_decorator(permission_required('scipost.can_view_production', raise_exception=True),
+                  name='dispatch')
+class UpdateEventView(UpdateView):
+    model = ProductionEvent
+    form_class = ProductionEventForm
+    slug_field = 'id'
+    slug_url_kwarg = 'event_id'
+
+    def get_queryset(self):
+        return self.model.objects.get_my_events(self.request.user.contributor)
+
+    def form_valid(self, form):
+        messages.success(self.request, 'Event updated succesfully')
+        return super().form_valid(form)
+
+
+@method_decorator(permission_required('scipost.can_view_production', raise_exception=True),
+                  name='dispatch')
+class DeleteEventView(DeleteView):
+    model = ProductionEvent
+    slug_field = 'id'
+    slug_url_kwarg = 'event_id'
+
+    def get_queryset(self):
+        return self.model.objects.get_my_events(self.request.user.contributor)
+
+    def form_valid(self, form):
+        messages.success(self.request, 'Event deleted succesfully')
+        return super().form_valid(form)
+
+    def get_success_url(self):
+        return self.object.get_absolute_url()
+
+
 @permission_required('scipost.can_publish_accepted_submission', return_403=True)
 def mark_as_completed(request, stream_id):
     stream = get_object_or_404(ProductionStream.objects.ongoing(), pk=stream_id)
-- 
GitLab