From ff27a8b7545589351e63d791cdab47abe235648a Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Wed, 20 Feb 2019 06:32:47 +0100
Subject: [PATCH] Add SubsidyAttachment management facilities

---
 finances/forms.py                             | 36 +++----------------
 finances/models.py                            |  2 ++
 .../templates/finances/_subsidy_card.html     | 26 ++++++++++++++
 .../templates/finances/subsidy_detail.html    | 13 -------
 finances/templates/finances/subsidy_list.html |  1 +
 .../subsidyattachment_confirm_delete.html     | 30 ++++++++++++++++
 .../finances/subsidyattachment_form.html      | 23 ++++++++++++
 finances/urls.py                              |  9 +++++
 finances/views.py                             | 33 ++++++++++++++++-
 partners/forms.py                             |  2 +-
 partners/views.py                             |  1 -
 11 files changed, 129 insertions(+), 47 deletions(-)
 create mode 100644 finances/templates/finances/subsidyattachment_confirm_delete.html
 create mode 100644 finances/templates/finances/subsidyattachment_form.html

diff --git a/finances/forms.py b/finances/forms.py
index 9142a9a9e..309d50d23 100644
--- a/finances/forms.py
+++ b/finances/forms.py
@@ -32,43 +32,17 @@ class SubsidyAttachmentForm(forms.ModelForm):
     class Meta:
         model = SubsidyAttachment
         fields = (
-            'name',
+            'subsidy',
             'attachment',
+            'name',
             'publicly_visible',
         )
 
-    def save(self, to_object, commit=True):
-        """
-        This custom save method will automatically assign the file to the object
-        given when it is a valid instance type.
-        """
-        attachment = super().save(commit=False)
-
-        # Formset might save an empty Instance
-        if not attachment.name or not attachment.attachment:
-            return None
-
-        if isinstance(to_object, Subsidy):
-            attachment.subsidy = to_object
-        else:
-            raise forms.ValidationError('You cannot save Attachments to this type of object.')
-        if commit:
-            attachment.save()
-        return attachment
-
-
-class SubsidyAttachmentFormSet(forms.BaseModelFormSet):
-    def save(self, to_object, commit=True):
-        """
-        This custom save method will automatically assign the file to the object
-        given when it is a valid instance type.
-        """
-        returns = []
-        for form in self.forms:
-            returns.append(form.save(to_object))
-        return returns
 
 
+#############
+# Work logs #
+#############
 
 class WorkLogForm(forms.ModelForm):
     def __init__(self, *args, **kwargs):
diff --git a/finances/models.py b/finances/models.py
index 3776c57fd..52778c3aa 100644
--- a/finances/models.py
+++ b/finances/models.py
@@ -66,6 +66,8 @@ class SubsidyAttachment(models.Model):
                                   blank=True)
     publicly_visible = models.BooleanField(default=False)
 
+    def __str__(self):
+        return '%s, attachment to %s' % (self.name, self.subsidy)
 
     def get_absolute_url(self):
         if self.subsidy:
diff --git a/finances/templates/finances/_subsidy_card.html b/finances/templates/finances/_subsidy_card.html
index e7168adcd..238cf70a4 100644
--- a/finances/templates/finances/_subsidy_card.html
+++ b/finances/templates/finances/_subsidy_card.html
@@ -39,4 +39,30 @@
     </div>
   </div>
 
+  <div class="row">
+    <div class="col-12">
+      <h3>Attachments</h3>
+      <table class="table">
+	<tr>
+	  <th>File name</th>
+	  <th>Publicly visible?</th>
+	</tr>
+	{% for att in subsidy.attachments.all %}
+	<tr>
+	  <td><a href="{{ att.get_absolute_url }}" target="_blank">{{ att.name }}</a></td>
+	  <td>{{ att.publicly_visible }}</td>
+	  {% if perms.scipost.can_manage_subsidies %}
+	  <td><a href="{% url 'finances:subsidyattachment_update' pk=att.id %}"><span class="text-warning">Update</span></a></td>
+	  <td><a href="{% url 'finances:subsidyattachment_delete' pk=att.id %}"><span class="text-danger">Delete</span></a></td>
+	  {% endif %}
+	</tr>
+	{% empty %}
+	<tr>
+	  <td>No attachment found</td>
+	</tr>
+	{% endfor %}
+      </table>
+    </div>
+  </div>
+
 </div>
diff --git a/finances/templates/finances/subsidy_detail.html b/finances/templates/finances/subsidy_detail.html
index 2dd44bbbb..ab90b4673 100644
--- a/finances/templates/finances/subsidy_detail.html
+++ b/finances/templates/finances/subsidy_detail.html
@@ -19,17 +19,4 @@
   </div>
 </div>
 
-<div class="row">
-  <div class="col-12">
-    <h3>Attachments</h3>
-    <ul>
-      {% for file in subsidy.attachments.all %}
-      <li><a href="{{ file.get_absolute_url }}" target="_blank">{{ file.name }}</a></li>
-      {% empty %}
-      <li>No attachment found</li>
-      {% endfor %}
-    </ul>
-  </div>
-</div>
-
 {% endblock content %}
diff --git a/finances/templates/finances/subsidy_list.html b/finances/templates/finances/subsidy_list.html
index e8a11c932..7a167e3d8 100644
--- a/finances/templates/finances/subsidy_list.html
+++ b/finances/templates/finances/subsidy_list.html
@@ -29,6 +29,7 @@ $(document).ready(function($) {
     {% if perms.scipost.can_manage_subsidies %}
     <ul>
       <li><a href="{% url 'finances:subsidy_create' %}">Add a Subsidy</a></li>
+      <li><a href="{% url 'finances:subsidyattachment_create' %}">Add a SubsidyAttachment</a></li>
     </ul>
     {% endif %}
   </div>
diff --git a/finances/templates/finances/subsidyattachment_confirm_delete.html b/finances/templates/finances/subsidyattachment_confirm_delete.html
new file mode 100644
index 000000000..282485633
--- /dev/null
+++ b/finances/templates/finances/subsidyattachment_confirm_delete.html
@@ -0,0 +1,30 @@
+{% extends 'finances/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+<span class="breadcrumb-item">Confirm deletetion</span>
+{% endblock %}
+
+{% block pagetitle %}: Delete SubsidyAttachment{% endblock pagetitle %}
+
+{% block content %}
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Delete SubsidyAttachment</h1>
+	{{ object }}
+    </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 SubsidyAttachment?</h3>
+      <input type="submit" class="btn btn-danger" value="Yes, delete it" />
+    </form>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/finances/templates/finances/subsidyattachment_form.html b/finances/templates/finances/subsidyattachment_form.html
new file mode 100644
index 000000000..2ae24e064
--- /dev/null
+++ b/finances/templates/finances/subsidyattachment_form.html
@@ -0,0 +1,23 @@
+{% extends 'finances/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+<span class="breadcrumb-item">{% if form.instance.id %}Update {{ form.instance }}{% else %}Add new SubsidyAttachment{% endif %}</span>
+{% endblock %}
+
+{% block pagetitle %}: SubsidyAttachments{% endblock pagetitle %}
+
+
+{% block content %}
+<div class="row">
+  <div class="col-12">
+    <form enctype="multipart/form-data" action="" method="post">
+      {% csrf_token %}
+      {{ form|bootstrap }}
+      <input type="submit" value="Submit" class="btn btn-primary">
+  </div>
+</div>
+{% endblock content %}
diff --git a/finances/urls.py b/finances/urls.py
index 0181a1fc9..243d70235 100644
--- a/finances/urls.py
+++ b/finances/urls.py
@@ -20,6 +20,15 @@ urlpatterns = [
     url(r'^subsidies/(?P<pk>[0-9]+)/$', views.SubsidyDetailView.as_view(), name='subsidy_details'),
     url(r'^subsidies/(?P<subsidy_id>[0-9]+)/attachments/(?P<attachment_id>[0-9]+)$',
         views.subsidy_attachment, name='subsidy_attachment'),
+    url(r'^subsidies/attachments/add/$',
+        views.SubsidyAttachmentCreateView.as_view(),
+        name='subsidyattachment_create'),
+    url(r'^subsidies/attachments/(?P<pk>[0-9]+)/update/$',
+        views.SubsidyAttachmentUpdateView.as_view(),
+        name='subsidyattachment_update'),
+    url(r'^subsidies/attachments/(?P<pk>[0-9]+)/delete/$',
+        views.SubsidyAttachmentDeleteView.as_view(),
+        name='subsidyattachment_delete'),
 
     # Timesheets
     url(r'^timesheets$', views.timesheets, name='timesheets'),
diff --git a/finances/views.py b/finances/views.py
index b0a747ede..f8471a9e5 100644
--- a/finances/views.py
+++ b/finances/views.py
@@ -15,7 +15,7 @@ from django.views.generic.detail import DetailView
 from django.views.generic.edit import CreateView, UpdateView, DeleteView
 from django.views.generic.list import ListView
 
-from .forms import SubsidyForm, LogsFilter
+from .forms import SubsidyForm, SubsidyAttachmentForm, LogsFilter
 from .models import Subsidy, SubsidyAttachment, WorkLog
 from .utils import slug_to_id
 
@@ -81,6 +81,37 @@ class SubsidyDetailView(DetailView):
     model = Subsidy
 
 
+class SubsidyAttachmentCreateView(PermissionsMixin, CreateView):
+    """
+    Create a new SubsidyAttachment.
+    """
+    permission_required = 'scipost.can_manage_subsidies'
+    model = SubsidyAttachment
+    form_class = SubsidyAttachmentForm
+    template_name = 'finances/subsidyattachment_form.html'
+    success_url = reverse_lazy('finances:subsidies')
+
+
+class SubsidyAttachmentUpdateView(PermissionsMixin, UpdateView):
+    """
+    Update a SubsidyAttachment.
+    """
+    permission_required = 'scipost.can_manage_subsidies'
+    model = SubsidyAttachment
+    form_class = SubsidyAttachmentForm
+    template_name = 'finances/subsidyattachment_form.html'
+    success_url = reverse_lazy('finances:subsidies')
+
+
+class SubsidyAttachmentDeleteView(PermissionsMixin, DeleteView):
+    """
+    Delete a SubsidyAttachment.
+    """
+    permission_required = 'scipost.can_manage_subsidies'
+    model = SubsidyAttachment
+    success_url = reverse_lazy('finances:subsidies')
+
+
 def subsidy_attachment(request, subsidy_id, attachment_id):
     attachment = get_object_or_404(SubsidyAttachment.objects,
                                    subsidy__id=subsidy_id, id=attachment_id)
diff --git a/partners/forms.py b/partners/forms.py
index aa34fb488..531850532 100644
--- a/partners/forms.py
+++ b/partners/forms.py
@@ -480,7 +480,7 @@ class MembershipQueryForm(forms.Form):
     captcha = ReCaptchaField(attrs={'theme': 'clean'}, label='*Please verify to continue:')
 
 
-#done
+# done
 class PartnersAttachmentForm(forms.ModelForm):
     class Meta:
         model = PartnersAttachment
diff --git a/partners/views.py b/partners/views.py
index 9bc5ea824..9ddb4324f 100644
--- a/partners/views.py
+++ b/partners/views.py
@@ -404,7 +404,6 @@ def agreement_details(request, agreement_id):
 
     if request.user.has_perm('scipost.can_manage_SPB'):
         form = MembershipAgreementForm(request.POST or None, instance=agreement)
-        PartnersAttachmentFormSet
 
         PartnersAttachmentFormset = modelformset_factory(PartnersAttachment,
                                                          PartnersAttachmentForm,
-- 
GitLab