From 9280f4b349a59f091da734ff7df6f695824dfebb Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Fri, 12 Jan 2018 20:06:39 +0100
Subject: [PATCH] Update Production to provide for Officer deletion

---
 .../migrations/0004_auto_20180112_1919.py     | 20 +++++++++++++++++
 production/managers.py                        |  5 +++++
 .../migrations/0003_productionuser_name.py    | 20 +++++++++++++++++
 .../migrations/0004_auto_20180112_1957.py     | 22 +++++++++++++++++++
 production/models.py                          | 12 ++++++----
 .../templates/production/production.html      |  9 ++++++--
 production/urls.py                            |  2 ++
 production/views.py                           | 18 +++++++++++++--
 8 files changed, 100 insertions(+), 8 deletions(-)
 create mode 100644 partners/migrations/0004_auto_20180112_1919.py
 create mode 100644 production/migrations/0003_productionuser_name.py
 create mode 100644 production/migrations/0004_auto_20180112_1957.py

diff --git a/partners/migrations/0004_auto_20180112_1919.py b/partners/migrations/0004_auto_20180112_1919.py
new file mode 100644
index 000000000..2bd79a5ac
--- /dev/null
+++ b/partners/migrations/0004_auto_20180112_1919.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-01-12 18:19
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('partners', '0003_institution_css_class'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='institution',
+            name='css_class',
+            field=models.CharField(blank=True, max_length=256, verbose_name='Additional logo CSS class'),
+        ),
+    ]
diff --git a/production/managers.py b/production/managers.py
index a88a6ed1c..fb0788d60 100644
--- a/production/managers.py
+++ b/production/managers.py
@@ -3,6 +3,11 @@ from django.db import models
 from . import constants
 
 
+class ProductionUserQuerySet(models.QuerySet):
+    def active(self):
+        return self.filter(user__isnull=False)
+
+
 class ProductionStreamQuerySet(models.QuerySet):
     def completed(self):
         return self.filter(status=constants.PRODUCTION_STREAM_COMPLETED)
diff --git a/production/migrations/0003_productionuser_name.py b/production/migrations/0003_productionuser_name.py
new file mode 100644
index 000000000..2084c70d5
--- /dev/null
+++ b/production/migrations/0003_productionuser_name.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-01-12 18:38
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('production', '0002_auto_20171229_1435'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='productionuser',
+            name='name',
+            field=models.CharField(blank=True, max_length=128),
+        ),
+    ]
diff --git a/production/migrations/0004_auto_20180112_1957.py b/production/migrations/0004_auto_20180112_1957.py
new file mode 100644
index 000000000..cc0d0d230
--- /dev/null
+++ b/production/migrations/0004_auto_20180112_1957.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-01-12 18:57
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('production', '0003_productionuser_name'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='productionuser',
+            name='user',
+            field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='production_user', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/production/models.py b/production/models.py
index 12c461b7d..54becc09e 100644
--- a/production/models.py
+++ b/production/models.py
@@ -8,7 +8,8 @@ from django.utils.functional import cached_property
 from .constants import PRODUCTION_STREAM_STATUS, PRODUCTION_STREAM_INITIATED, PRODUCTION_EVENTS,\
                        EVENT_MESSAGE, EVENT_HOUR_REGISTRATION, PRODUCTION_STREAM_COMPLETED,\
                        PROOFS_STATUSES, PROOFS_UPLOADED
-from .managers import ProductionStreamQuerySet, ProductionEventManager, ProofsQuerySet
+from .managers import ProductionStreamQuerySet, ProductionEventManager, ProofsQuerySet,\
+                      ProductionUserQuerySet
 from .utils import proofs_id_to_slug
 
 from finances.models import WorkLog
@@ -21,12 +22,15 @@ class ProductionUser(models.Model):
     to relate all production related actions to.
     """
     user = models.OneToOneField(User, on_delete=models.PROTECT, unique=True,
-                                related_name='production_user')
+                                related_name='production_user', null=True)
+    name = models.CharField(max_length=128, blank=True)
 
-    # objects = ProductionUserQuerySet.as_manager()  -- Not implemented yet
+    objects = ProductionUserQuerySet.as_manager()
 
     def __str__(self):
-        return '%s, %s' % (self.user.last_name, self.user.first_name)
+        if self.user:
+            return '%s, %s' % (self.user.last_name, self.user.first_name)
+        return '%s (deactivated)' % self.name
 
 
 class ProductionStream(models.Model):
diff --git a/production/templates/production/production.html b/production/templates/production/production.html
index caf432ea2..8198157be 100644
--- a/production/templates/production/production.html
+++ b/production/templates/production/production.html
@@ -83,7 +83,7 @@
 
         </div>
         <div class="col-6">
-            <div class="card center-loader" id="details">
+            <div class="card center-loader bg-white" id="details">
                 {% if stream %}
                     {% include 'production/partials/production_stream_card.html' %}
                 {% else %}
@@ -144,7 +144,12 @@
           <h3>Current Production Team</h3>
           <ul>
               {% for officer in production_officers %}
-                <li>{{ officer }}</li>
+                <li>{{ officer }}
+                    <form action="{% url 'production:delete_officer' officer.id %}" class="d-inline px-1" method="post">
+                      {% csrf_token %}
+                      <input type="submit" class="btn btn-danger mb-1" value="Remove Officer">
+                  </form>
+              </li>
               {% endfor %}
           </ul>
 
diff --git a/production/urls.py b/production/urls.py
index e0ecebf5d..f1419f395 100644
--- a/production/urls.py
+++ b/production/urls.py
@@ -7,6 +7,8 @@ urlpatterns = [
     url(r'^(?P<stream_id>[0-9]+)$', production_views.production, name='production'),
     url(r'^completed$', production_views.completed, name='completed'),
     url(r'^officers/new$', production_views.user_to_officer, name='user_to_officer'),
+    url(r'^officers/(?P<officer_id>[0-9]+)/delete$', production_views.delete_officer,
+        name='delete_officer'),
     url(r'^streams/(?P<stream_id>[0-9]+)$',
         production_views.stream, name='stream'),
     url(r'^streams/(?P<stream_id>[0-9]+)/status$',
diff --git a/production/views.py b/production/views.py
index f368999aa..52dc38d16 100644
--- a/production/views.py
+++ b/production/views.py
@@ -68,10 +68,10 @@ def production(request, stream_id=None):
             pass
 
     if request.user.has_perm('scipost.can_view_timesheets'):
-        context['production_team'] = ProductionUser.objects.all()
+        context['production_team'] = ProductionUser.objects.active()
 
     if request.user.has_perm('scipost.can_promote_to_production_team'):
-        context['production_officers'] = ProductionUser.objects.all()
+        context['production_officers'] = ProductionUser.objects.active()
         context['new_officer_form'] = UserToOfficerForm()
     return render(request, 'production/production.html', context)
 
@@ -146,6 +146,20 @@ def user_to_officer(request):
     return redirect(reverse('production:production'))
 
 
+@is_production_user()
+@permission_required('scipost.can_promote_user_to_production_officer')
+def delete_officer(request, officer_id):
+    production_user = get_object_or_404(ProductionUser.objects.active(), id=officer_id)
+    production_user.name = '{first_name} {last_name}'.format(
+        first_name=production_user.user.first_name,
+        last_name=production_user.user.last_name)
+    production_user.user = None
+    production_user.save()
+
+    messages.success(request, '{user} removed as Production Officer'.format(user=production_user))
+    return redirect(reverse('production:production'))
+
+
 @is_production_user()
 @permission_required('scipost.can_take_decisions_related_to_proofs', raise_exception=True)
 def update_status(request, stream_id):
-- 
GitLab