diff --git a/production/managers.py b/production/managers.py index 4379df507a866763f71b20687f4954bfe3eb16bb..ca9b5d0ba99fb56cdce96d96963337445f27d16e 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 f2ec3b93c777423f1a78afc43a799dd23a8458ee..27e8c6a15785bcbae6c3d711889e7117f97b08e7 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 5903e476850d4d3546993abe082171bd99fdcfd2..e7d168b13c52553b541c78e7768c03fb95d45049 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 %} + · <a href="{% url 'production:update_event' event.id %}">Edit</a> + · <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 138be8b930faf2d4480a90af4aba7f2cbc8e3efc..fab873137020f491df123ae44c3c644fbef996d3 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 0bb839176ee0a6c60ac90c45daa0f6910a424979..ec8c987bf49ae30761f30bdce4d21b438e601353 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 21f99291149885c7f6845ac76e8896d544decebd..40f12bcc417bf4cee25452b0d8bf2651efef68b7 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 0000000000000000000000000000000000000000..d279e44da8b0cf874a552d3ddf6c41847a3dfbc8 --- /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 0000000000000000000000000000000000000000..fc90e04c976d7d7315c0ee5f2e590cabf349d448 --- /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 3ff66bdb86cc57bdd8a1bf8a79cf9457a0a60f14..cc5bf527b92c39690aabca17762514101ff57daf 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 abbbe447064714199d5f7c31a244618a3f568f25..0a7536f6a3c0f4de8f0e0e13250ddfc462497e09 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)