diff --git a/finances/forms.py b/finances/forms.py
index 9142a9a9e1a3152ebb158cf96108af0bd9266557..4fbafdb8da41d7409469b87113160b86456da05c 100644
--- a/finances/forms.py
+++ b/finances/forms.py
@@ -25,50 +25,23 @@ class SubsidyForm(forms.ModelForm):
         model = Subsidy
         fields = ['organization', 'subsidy_type', 'description',
                   'amount', 'amount_publicly_shown', 'status',
-                  'date', 'date_until']
+                  'date', 'date_until', 'renewable', 'renewal_of']
 
 
 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/migrations/0013_subsidy_renewal_of.py b/finances/migrations/0013_subsidy_renewal_of.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e12a516903349f25e6f941df9c0a5c530f55d79
--- /dev/null
+++ b/finances/migrations/0013_subsidy_renewal_of.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2019-02-23 10:49
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('finances', '0012_subsidyattachment'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='subsidy',
+            name='renewal_of',
+            field=models.ManyToManyField(blank=True, related_name='renewed_by', to='finances.Subsidy'),
+        ),
+    ]
diff --git a/finances/migrations/0014_subsidy_renewable.py b/finances/migrations/0014_subsidy_renewable.py
new file mode 100644
index 0000000000000000000000000000000000000000..e08fe96252b20ead4b2c5367b183fe8268e9f6b8
--- /dev/null
+++ b/finances/migrations/0014_subsidy_renewable.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2019-02-24 05:13
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('finances', '0013_subsidy_renewal_of'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='subsidy',
+            name='renewable',
+            field=models.NullBooleanField(),
+        ),
+    ]
diff --git a/finances/models.py b/finances/models.py
index cd3c7012e4952a24a52da731b5afcb61a6db77a1..fbc0ac257c17ac8c2cfad17c6b2099b33c958e06 100644
--- a/finances/models.py
+++ b/finances/models.py
@@ -2,6 +2,8 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
+import datetime
+
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.fields import GenericForeignKey
@@ -10,7 +12,7 @@ from django.urls import reverse
 from django.utils import timezone
 from django.utils.html import format_html
 
-from .constants import SUBSIDY_TYPES, SUBSIDY_STATUS
+from .constants import SUBSIDY_TYPES, SUBSIDY_TYPE_SPONSORSHIPAGREEMENT, SUBSIDY_STATUS
 from .utils import id_to_slug
 
 from scipost.storage import SecureFileStorage
@@ -42,6 +44,9 @@ class Subsidy(models.Model):
     status = models.CharField(max_length=32, choices=SUBSIDY_STATUS)
     date = models.DateField()
     date_until = models.DateField(blank=True, null=True)
+    renewable = models.NullBooleanField()
+    renewal_of = models.ManyToManyField('self', related_name='renewed_by',
+                                        symmetrical=False, blank=True)
 
     class Meta:
         verbose_name_plural = 'subsidies'
@@ -54,6 +59,37 @@ class Subsidy(models.Model):
     def get_absolute_url(self):
         return reverse('finances:subsidy_details', args=(self.id,))
 
+    @property
+    def renewal_action_date(self):
+        if self.date_until and self.subsidy_type == SUBSIDY_TYPE_SPONSORSHIPAGREEMENT:
+            return self.date_until - datetime.timedelta(days=122)
+        return '-'
+
+    @property
+    def renewal_action_date_color_class(self):
+        if self.date_until and self.renewable:
+            if self.renewed_by.exists():
+                return 'transparent'
+            today = datetime.date.today()
+            if self.date_until < today + datetime.timedelta(days=122):
+                return 'danger'
+            elif self.date_until < today + datetime.timedelta(days=153):
+                return 'warning'
+            return 'success'
+        return 'transparent'
+
+    @property
+    def date_until_color_class(self):
+        if self.date_until and self.renewable:
+            if self.renewed_by.exists():
+                return 'transparent'
+            today = datetime.date.today()
+            if self.date_until < today:
+                return 'warning'
+            else:
+                return 'success'
+        return 'transparent'
+
 
 class SubsidyAttachment(models.Model):
     """
@@ -66,11 +102,19 @@ 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:
             return reverse('finances:subsidy_attachment', args=(self.subsidy.id, self.id))
 
+    def visible_to_user(self, current_user):
+        if self.publicly_visible or current_user.has_perm('scipost.can_manage_subsidies'):
+            return True
+        if self.subsidy.organization.contactrole_set.filter(contact__user=current_user).exists():
+            return True
+        return False
 
 
 ###########################
diff --git a/finances/templates/finances/_subsidy_card.html b/finances/templates/finances/_subsidy_card.html
index e7168adcd386d086873b36df8789e6ba30579b51..2f21e32f6823c6b3b46e7243795e73bca4522669 100644
--- a/finances/templates/finances/_subsidy_card.html
+++ b/finances/templates/finances/_subsidy_card.html
@@ -35,6 +35,54 @@
 	  <td>Date until:</td><td>{{ subsidy.date_until }}</td>
 	</tr>
 	{% endif %}
+	{% if perms.scipost.can_manage_subsidies %}
+	<tr>
+	  <td>Renewable?</td><td>{% if subsidy.renewable == True %}Yes, renewal action date: <span class="bg-{{ subsidy.renewal_action_date_color_class }}">{{ subsidy.renewal_action_date }}</span>{% elif subsidy.renewable == None %}Undetermined [please update]{% else %}No{% endif %}</td>
+	</tr>
+	{% endif %}
+      </table>
+
+      {% if subsidy.renewal_of.all|length > 0 %}
+      <p>
+	Renewal of:<ul>{% for prevsub in subsidy.renewal_of.all %}<li><a href="{% url 'finances:subsidy_details' pk=prevsub.id %}">{{ prevsub }}</a></li>{% endfor %}</ul>
+      </p>
+      {% endif %}
+      {% if subsidy.renewed_by.all|length > 0 %}
+      <p>
+	Renewed by:<ul>{% for newsub in subsidy.renewed_by.all %}<li><a href="{% url 'finances:subsidy_details' pk=newsub.id %}">{{ newsub }}</a></li>{% endfor %}</ul>
+      </p>
+      {% endif %}
+
+    </div>
+  </div>
+
+  <div class="row">
+    <div class="col-12">
+      <h3>Attachments</h3>
+      {% if perms.scipost.can_manage_subsidies %}
+      <ul>
+	<li><a href="{% url 'finances:subsidyattachment_create' subsidy_id=subsidy.id %}">Add a SubsidyAttachment</a> to this Subsidy</li>
+      </ul>
+      {% endif %}
+      <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>{% if att.publicly_visible %}<i class="fa fa-check-circle text-success"></i>{% else %}<i class="fa fa-times-circle text-danger"></i>{% endif %}</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>
diff --git a/finances/templates/finances/subsidy_detail.html b/finances/templates/finances/subsidy_detail.html
index 2dd44bbbb4efe6cb0cf66e4a2a37c945bad50a54..ab90b4673d71649e813e958dacb25b70ad32bfee 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 e8a11c93262fd3a946ca40c8c83ce4130167df90..84be3dee1e2ef9c98da5b62529b1a8b4617b0579 100644
--- a/finances/templates/finances/subsidy_list.html
+++ b/finances/templates/finances/subsidy_list.html
@@ -3,7 +3,7 @@
 {% block pagetitle %}: Subsidies{% endblock pagetitle %}
 
 {% load staticfiles %}
-
+{% load bootstrap %}
 
 {% block headsup %}
 <script type="text/javascript">
@@ -53,7 +53,7 @@ $(document).ready(function($) {
 	    <a href="{% url 'finances:subsidies' %}"><i class="fa fa-sort-desc"></i></a>
 	    {% endif %}
 	  </th>
-	  <th>Date
+	  <th>From date
 	    {% if request.GET.ordering != 'asc' %}
 	    <a href="?order_by=date&ordering=asc"><i class="fa fa-sort-asc"></i></a>
 	    {% else %}
@@ -65,19 +65,48 @@ $(document).ready(function($) {
 	    <a href="{% url 'finances:subsidies' %}"><i class="fa fa-sort-desc"></i></a>
 	    {% endif %}
 	  </th>
+	  <th>Until
+	    {% if request.GET.ordering != 'asc' %}
+	    <a href="?order_by=until&ordering=asc"><i class="fa fa-sort-asc"></i></a>
+	    {% else %}
+	    <a href="{% url 'finances:subsidies' %}"><i class="fa fa-sort-asc"></i></a>
+	    {% endif %}
+	    {% if request.GET.ordering != 'desc' %}
+	    <a href="?order_by=until&ordering=desc"><i class="fa fa-sort-desc"></i></a>
+	    {% else %}
+	    <a href="{% url 'finances:subsidies' %}"><i class="fa fa-sort-desc"></i></a>
+	    {% endif %}
+	  </th>
+	  {% if perms.scipost.can_manage_subsidies %}
+	  <th><span class="small" style="writing-mode: vertical-lr;">Renewable?</span></th>
+	  <th><span class="small" style="writing-mode: vertical-lr;">Renewed?</span></th>
+	  <th>Renewal<br/>action date</th>
+	  {% endif %}
 	</tr>
       </thead>
       <tbody>
 	{% for subsidy in object_list %}
 	<tr class="table-row" data-href="{% url 'finances:subsidy_details' pk=subsidy.id %}" style="cursor: pointer;">
 	  <td>{{ subsidy.organization }}</td>
-	  <td>{{ subsidy.get_subsidy_type_display }}</td>
+	  <td>{{ subsidy.get_subsidy_type_display }}
+	    {% if subsidy.renewal_of.all|length > 0 %}<br/><span class="small text-muted">Renewal of:<ul class="list-unstyled">{% for prevsub in subsidy.renewal_of.all %}<li>{{ prevsub }}</li>{% endfor %}</ul></span>{% endif %}
+	    {% if subsidy.renewed_by.all|length > 0 %}<br/><span class="small text-muted">Renewed by:<ul class="list-unstyled">{% for newsub in subsidy.renewed_by.all %}<li>{{ newsub }}</li>{% endfor %}</ul></span>{% endif %}	  </td>
 	  <td>{% if subsidy.amount_publicly_shown or perms.scipost.can_manage_subsidies %}&euro;{{ subsidy.amount }}{% else %}-{% endif %}</td>
 	  <td>{{ subsidy.date }}</td>
+	  <td class="bg-{{ subsidy.date_until_color_class }}">{{ subsidy.date_until }}</td>
+	  {% if perms.scipost.can_manage_subsidies %}
+	  <td>
+	    {% if subsidy.renewable == True %}<i class="fa fa-check-circle text-success"></i>{% elif subsidy.renewable == False %}<i class="fa fa-times-circle text-danger"></i>{% else %}<i class="fa fa-question-circle text-warning"></i>{% endif %}
+	  </td>
+	  <td>
+	    {% if subsidy.renewed_by.all|length > 0 %}<i class="fa fa-check-circle text-success"></i>{% else %}<i class="fa fa-times-circle text-danger"></i>{% endif %}
+	  </td>
+	  <td class="bg-{{ subsidy.renewal_action_date_color_class }}">{{ subsidy.renewal_action_date }}</td>
+	  {% endif %}
 	</tr>
 	{% empty %}
 	<tr>
-	  <td colspan="4">No Subsidy found</td>
+	  <td colspan="5">No Subsidy found</td>
 	</tr>
 	{% endfor %}
       </tbody>
diff --git a/finances/templates/finances/subsidyattachment_confirm_delete.html b/finances/templates/finances/subsidyattachment_confirm_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..282485633abebd3a4aeeda0028870cb9ab74b830
--- /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 0000000000000000000000000000000000000000..2ae24e0641457d4b915f85c2ce34812746df9cc3
--- /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 0181a1fc976a140233cac2d39543fd14331f0b6c..dd19ee96e037d62437157afd3b1331b0b8a06cf5 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/(?P<subsidy_id>[0-9]+)/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 3cd4089fdfae2a7f8f20616ab5acd389f413b278..b6394fee1487bf20f4b2fdd49cdf0077eea04079 100644
--- a/finances/views.py
+++ b/finances/views.py
@@ -7,6 +7,7 @@ import mimetypes
 from django.contrib import messages
 from django.contrib.auth.decorators import permission_required
 from django.contrib.auth.mixins import LoginRequiredMixin
+from django.core.exceptions import PermissionDenied
 from django.core.urlresolvers import reverse_lazy
 from django.http import Http404, HttpResponse
 from django.shortcuts import get_object_or_404, render
@@ -14,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
 
@@ -34,7 +35,9 @@ class SubsidyCreateView(PermissionsMixin, CreateView):
     model = Subsidy
     form_class = SubsidyForm
     template_name = 'finances/subsidy_form.html'
-    success_url = reverse_lazy('finances:subsidies')
+
+    def get_success_url(self):
+        return reverse_lazy('finances:subsidy_details', kwargs={'pk': self.object.id})
 
 
 class SubsidyUpdateView(PermissionsMixin, UpdateView):
@@ -45,7 +48,9 @@ class SubsidyUpdateView(PermissionsMixin, UpdateView):
     model = Subsidy
     form_class = SubsidyForm
     template_name = 'finances/subsidy_form.html'
-    success_url = reverse_lazy('finances:subsidies')
+
+    def get_success_url(self):
+        return reverse_lazy('finances:subsidy_details', kwargs={'pk': self.object.id})
 
 
 class SubsidyDeleteView(PermissionsMixin, DeleteView):
@@ -71,6 +76,8 @@ class SubsidyListView(ListView):
             qs = qs.filter(amount_publicly_shown=True).order_by('amount')
         elif order_by == 'date':
             qs = qs.order_by('date')
+        elif order_by == 'until':
+            qs = qs.order_by('date_until')
         if ordering == 'desc':
             qs = qs.reverse()
         return qs
@@ -80,10 +87,53 @@ 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'
+
+    def get_success_url(self):
+        return reverse_lazy('finances:subsidy_details', kwargs={'pk': self.object.subsidy.id})
+
+    def get_initial(self):
+        subsidy = get_object_or_404(Subsidy, pk=self.kwargs.get('subsidy_id'))
+        return {'subsidy': subsidy}
+
+
+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')
+
+    def get_success_url(self):
+        return reverse_lazy('finances:subsidy_details', kwargs={'pk': self.object.subsidy.id})
+
+
+class SubsidyAttachmentDeleteView(PermissionsMixin, DeleteView):
+    """
+    Delete a SubsidyAttachment.
+    """
+    permission_required = 'scipost.can_manage_subsidies'
+    model = SubsidyAttachment
+
+    def get_success_url(self):
+        return reverse_lazy('finances:subsidy_details', kwargs={'pk': self.object.subsidy.id})
+
+
 def subsidy_attachment(request, subsidy_id, attachment_id):
     attachment = get_object_or_404(SubsidyAttachment.objects,
                                    subsidy__id=subsidy_id, id=attachment_id)
-
+    if not attachment.visible_to_user(request.user):
+        raise PermissionDenied
     content_type, encoding = mimetypes.guess_type(attachment.attachment.path)
     content_type = content_type or 'application/octet-stream'
     response = HttpResponse(attachment.attachment.read(), content_type=content_type)
diff --git a/organizations/admin.py b/organizations/admin.py
index 5678d6d23f437fae008d348db6195b555776eeed..ad400ea0d6ea65bfea3cd60b7e15a20d554c6cf6 100644
--- a/organizations/admin.py
+++ b/organizations/admin.py
@@ -4,6 +4,8 @@ __license__ = "AGPL v3"
 
 from django.contrib import admin
 
+from guardian.admin import GuardedModelAdmin
+
 from .models import Organization, OrganizationEvent, ContactPerson, Contact, ContactRole
 
 
@@ -15,7 +17,7 @@ class ContactPersonInline(admin.TabularInline):
     model = ContactPerson
     extra = 0
 
-class OrganizationAdmin(admin.ModelAdmin):
+class OrganizationAdmin(GuardedModelAdmin):
     inlines = [OrganizationEventInline, ContactPersonInline,]
     search_fields = ['name', 'acronym']
 
@@ -33,3 +35,11 @@ class ContactAdmin(admin.ModelAdmin):
 
 
 admin.site.register(Contact, ContactAdmin)
+
+
+class ContactInline(admin.TabularInline):
+    """
+    For use as an inline in User admin.
+    """
+    model = Contact
+    extra = 0
diff --git a/organizations/decorators.py b/organizations/decorators.py
new file mode 100644
index 0000000000000000000000000000000000000000..c517f1665dbf5befc29b5118eaa5d4155515a978
--- /dev/null
+++ b/organizations/decorators.py
@@ -0,0 +1,14 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from .models import Contact
+
+
+def has_contact(user):
+    """Requires user to be related to a Contact."""
+    try:
+        user.org_contact
+        return True
+    except Contact.DoesNotExist:
+        return False
diff --git a/organizations/forms.py b/organizations/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..383e87261c4482d902ac2342263cae3a8006b149
--- /dev/null
+++ b/organizations/forms.py
@@ -0,0 +1,220 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+import datetime
+
+from django import forms
+
+from django.contrib.auth.models import User, Group
+from django.contrib.auth.password_validation import validate_password
+from django.core.exceptions import ValidationError
+from django.db import transaction
+from django.utils import timezone
+
+from guardian.shortcuts import assign_perm
+
+from .constants import ROLE_GENERAL
+from .models import OrganizationEvent, ContactPerson, Contact, ContactRole
+
+from scipost.constants import TITLE_CHOICES
+
+
+class OrganizationEventForm(forms.ModelForm):
+    class Meta:
+        model = OrganizationEvent
+        fields = ['organization', 'event', 'comments', 'noted_on', 'noted_by']
+
+
+class ContactPersonForm(forms.ModelForm):
+    class Meta:
+        model = ContactPerson
+        fields = '__all__'
+
+    def clean_email(self):
+        """
+        Check if the email is already associated to an existing ContactPerson or Contact.
+        """
+        email = self.cleaned_data['email']
+        try:
+            ContactPerson.objects.get(email=email)
+            if self.instance.pk:
+                pass  # OK, this is an update
+            else:
+                self.add_error('email', 'This email is already associated to a Contact Person.')
+        except ContactPerson.DoesNotExist:
+            pass
+        try:
+            Contact.objects.get(user__email=email)
+            self.add_error('email', 'This email is already associated to a Contact.')
+        except Contact.DoesNotExist:
+            pass
+        return email
+
+
+class UpdateContactDataForm(forms.ModelForm):
+    """
+    This form is used in the scipost:update_personal_data method.
+    """
+    class Meta:
+        model = Contact
+        fields = ['title']
+
+
+class ContactForm(forms.ModelForm):
+    """
+    This Contact form is mainly used for editing Contact instances.
+    """
+    class Meta:
+        model = Contact
+        fields = ['title', 'key_expires']
+
+
+class NewContactForm(ContactForm):
+    """
+    This Contact form is used to create new Contact instances, as it will also handle
+    possible sending and activation of User instances coming with the new Contact.
+    """
+    title = forms.ChoiceField(choices=TITLE_CHOICES, label='Title')
+    first_name = forms.CharField()
+    last_name = forms.CharField()
+    email = forms.CharField()
+    existing_user = None
+
+    def __init__(self, *args, **kwargs):
+        """
+        Organization is a required argument to tell the formset which Organization
+        the Contact is being edited for in the current form.
+        """
+        self.organization = kwargs.pop('organization')
+        self.contactperson = kwargs.pop('contactperson')
+        super().__init__(*args, **kwargs)
+
+    def clean_email(self):
+        """
+        Check if User already is known in the system.
+        """
+        email = self.cleaned_data['email']
+        try:
+            self.existing_user = User.objects.get(email=email)
+            if not self.data.get('confirm_use_existing', '') == 'on':
+                # Do not give error if user wants to use existing User
+                self.add_error('email', 'This User is already registered.')
+            self.fields['confirm_use_existing'] = forms.BooleanField(
+                required=False, initial=False, label='Use the existing user instead: %s %s'
+                                                     % (self.existing_user.first_name,
+                                                        self.existing_user.last_name))
+        except User.DoesNotExist:
+            pass
+        return email
+
+    @transaction.atomic
+    def save(self, current_user, commit=True):
+        """
+        If existing user is found, link it to the Organization.
+        """
+        if self.existing_user and self.data.get('confirm_use_existing', '') == 'on':
+            # Create new Contact if it doesn't already exist
+            try:
+                contact = self.existing_user.org_contact
+            except Contact.DoesNotExist:
+                contact = super().save(commit=False)
+                contact.title = self.existing_user.org_contact.title
+                contact.user = self.existing_user
+                contact.save()
+            # Assign permissions and Group
+            assign_perm('can_view_org_contacts', contact.user, self.organization)
+            orgcontacts = Group.objects.get(name='Organization Contacts')
+            contact.user.groups.add(orgcontacts)
+        else:
+            # Create complete new Account (User + Contact)
+            user = User(
+                first_name=self.cleaned_data['first_name'],
+                last_name=self.cleaned_data['last_name'],
+                email=self.cleaned_data['email'],
+                username=self.cleaned_data['email'],
+                is_active=False,
+            )
+            user.save()
+            contact = Contact(
+                user=user,
+                title=self.cleaned_data['title']
+            )
+            contact.generate_key()
+            contact.save()
+
+            # Assign permissions and Group
+            assign_perm('can_view_org_contacts', user, self.organization)
+            orgcontacts = Group.objects.get(name='Organization Contacts')
+            user.groups.add(orgcontacts)
+
+        # Create the role with to-be-updated info
+        contactrole = ContactRole(
+            contact=contact,
+            organization=self.organization,
+            kind=[ROLE_GENERAL,],
+            date_from=timezone.now(),
+            date_until=timezone.now() + datetime.timedelta(days=3650)
+        )
+        contactrole.save()
+
+        # If upgrading from a ContactPerson, delete the latter
+        if self.contactperson:
+            self.contactperson.delete()
+
+        return contact
+
+
+class ContactActivationForm(forms.ModelForm):
+    class Meta:
+        model = User
+        fields = []
+
+    password_new = forms.CharField(label='* Password', widget=forms.PasswordInput())
+    password_verif = forms.CharField(label='* Verify password', widget=forms.PasswordInput(),
+                                     help_text='Your password must contain at least 8 characters')
+
+    def clean(self, *args, **kwargs):
+        try:
+            self.instance.org_contact
+        except Contact.DoesNotExist:
+            self.add_error(None, 'Your account is invalid, please contact the administrator.')
+        return super().clean(*args, **kwargs)
+
+    def clean_password(self):
+        password = self.cleaned_data.get('password_new', '')
+        try:
+            validate_password(password, self.instance)
+        except ValidationError as error_message:
+            self.add_error('password_new', error_message)
+        return password
+
+    def clean_password_verif(self):
+        if self.cleaned_data.get('password_new', '') != self.cleaned_data.get('password_verif', ''):
+            self.add_error('password_verif', 'Your password entries must match')
+        return self.cleaned_data.get('password_verif', '')
+
+    @transaction.atomic
+    def activate_user(self):
+        if self.errors:
+            return forms.ValidationError
+
+        # Activate account
+        self.instance.is_active = True
+        self.instance.set_password(self.cleaned_data['password_new'])
+        self.instance.save()
+
+        return self.instance
+
+
+class ContactRoleForm(forms.ModelForm):
+
+    class Meta:
+        model = ContactRole
+        fields = '__all__'
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        if self.instance.id:
+            self.fields['organization'].disabled = True
+            self.fields['contact'].disabled = True
diff --git a/organizations/management/commands/transfer_contact_data.py b/organizations/management/commands/transfer_contact_data.py
new file mode 100644
index 0000000000000000000000000000000000000000..f34bc7463fa0fd8f24a21f1424febffd9fe06d9c
--- /dev/null
+++ b/organizations/management/commands/transfer_contact_data.py
@@ -0,0 +1,48 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+import datetime
+
+from django.contrib.auth.models import Group
+from django.core.management.base import BaseCommand
+from django.utils import timezone
+
+from guardian.shortcuts import assign_perm
+
+from partners.models import Partner
+
+from organizations.models import Contact, ContactRole
+
+
+class Command(BaseCommand):
+    help = ('For Partners, transfer the data of partners.Contact instances '
+            'to organizations.Contact and ContactRole instances. '
+            'This is meant as a temporary, one-off method to be used during '
+            'deprecation of (Prospective)Partners.')
+
+    def handle(self, *args, **kwargs):
+        for partner in Partner.objects.all():
+            for oldcontact in partner.contact_set.all():
+                contact = Contact(
+                    user=oldcontact.user,
+                    title=oldcontact.title,
+                    activation_key=oldcontact.activation_key,
+                    key_expires=oldcontact.key_expires
+                )
+                contact.save()
+
+                # Assign permissions and Group
+                assign_perm('can_view_org_contacts', oldcontact.user, partner.organization)
+                orgcontacts = Group.objects.get(name='Organization Contacts')
+                oldcontact.user.groups.add(orgcontacts)
+
+                contactrole = ContactRole(
+                    contact=contact,
+                    organization=partner.organization,
+                    kind=oldcontact.kind,
+                    date_from=timezone.now(),
+                    date_until=timezone.now() + datetime.timedelta(days=3650)
+                )
+                contactrole.save()
+                oldcontact.delete()
diff --git a/organizations/migrations/0007_auto_20190221_0553.py b/organizations/migrations/0007_auto_20190221_0553.py
new file mode 100644
index 0000000000000000000000000000000000000000..38983e2041bb709d1d55e85318739f86ca7a8be0
--- /dev/null
+++ b/organizations/migrations/0007_auto_20190221_0553.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2019-02-21 04:53
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organizations', '0006_auto_20190219_2058'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='organization',
+            options={'ordering': ['country', 'name'], 'permissions': (('can_view_org_contacts', "Can view this Organization's Contacts"),)},
+        ),
+    ]
diff --git a/organizations/migrations/0008_auto_20190222_1120.py b/organizations/migrations/0008_auto_20190222_1120.py
new file mode 100644
index 0000000000000000000000000000000000000000..afbad95fbed4dfdb1df9346da9fd0c3db7ed5b4d
--- /dev/null
+++ b/organizations/migrations/0008_auto_20190222_1120.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2019-02-22 10:20
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organizations', '0007_auto_20190221_0553'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='contact',
+            options={'ordering': ['user__last_name', 'user__first_name']},
+        ),
+    ]
diff --git a/organizations/migrations/0009_auto_20190223_1001.py b/organizations/migrations/0009_auto_20190223_1001.py
new file mode 100644
index 0000000000000000000000000000000000000000..c93eb96c7cc628ef24fda101a2794696bf0ea790
--- /dev/null
+++ b/organizations/migrations/0009_auto_20190223_1001.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2019-02-23 09:01
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organizations', '0008_auto_20190222_1120'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='contactperson',
+            options={'ordering': ['last_name', 'first_name', 'organization']},
+        ),
+    ]
diff --git a/organizations/migrations/0010_auto_20190223_1406.py b/organizations/migrations/0010_auto_20190223_1406.py
new file mode 100644
index 0000000000000000000000000000000000000000..b7b78e4e2b0c73d1c02661e4d8c02ec759b6271c
--- /dev/null
+++ b/organizations/migrations/0010_auto_20190223_1406.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2019-02-23 13:06
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organizations', '0009_auto_20190223_1001'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='organizationevent',
+            options={'ordering': ['-noted_on', 'organization']},
+        ),
+    ]
diff --git a/organizations/models.py b/organizations/models.py
index 75f1e5833e587aecfedfb374f7d063660f3cbeab..79e737012952270deb8a2eaf46a96c104733eff3 100644
--- a/organizations/models.py
+++ b/organizations/models.py
@@ -75,6 +75,9 @@ class Organization(models.Model):
 
     class Meta:
         ordering = ['country', 'name']
+        permissions = (
+            ('can_view_org_contacts', 'Can view this Organization\'s Contacts'),
+        )
 
     def __str__(self):
         return self.name
@@ -165,6 +168,15 @@ class Organization(models.Model):
         """
         return self.subsidy_set.filter(date_until__gte=datetime.date.today()).exists()
 
+    @property
+    def latest_subsidy_date_until(self):
+        """
+        Returns the end date of validity of the latest subsidy.
+        """
+        if self.subsidy_set:
+            return self.subsidy_set.order_by('-date_until').first().date_until
+        return '-'
+
     def get_total_subsidies_obtained(self, n_years_past=None):
         """
         Computes the total amount received by SciPost, in the form
@@ -198,6 +210,9 @@ class OrganizationEvent(models.Model):
     noted_on = models.DateTimeField(default=timezone.now)
     noted_by = models.ForeignKey(User, on_delete=models.CASCADE)
 
+    class Meta:
+        ordering = ['-noted_on', 'organization']
+
     def __str__(self):
         return '%s: %s' % (str(self.organization), self.get_event_display())
 
@@ -222,6 +237,9 @@ class ContactPerson(models.Model):
     email = models.EmailField()
     role = models.CharField(max_length=128)
 
+    class Meta:
+        ordering = ['last_name', 'first_name', 'organization']
+
     def __str__(self):
         return "%s %s %s" % (self.get_title_display(), self.first_name, self.last_name)
 
@@ -237,6 +255,9 @@ class Contact(models.Model):
     activation_key = models.CharField(max_length=40, blank=True)
     key_expires = models.DateTimeField(default=timezone.now)
 
+    class Meta:
+        ordering = ['user__last_name', 'user__first_name']
+
     def __str__(self):
         return '%s %s, %s' % (self.get_title_display(), self.user.last_name, self.user.first_name)
 
@@ -259,8 +280,8 @@ class Contact(models.Model):
 
 class ContactRole(models.Model):
     """
-    A ContactRole instance links a Contact to an Organization, for a specific period of
-    time, and for a specific period in time.
+    A ContactRole instance links a Contact to an Organization, for a specific set of roles
+    and for a specific period in time.
     """
     contact = models.ForeignKey('organizations.Contact', on_delete=models.CASCADE,
                                 related_name='roles')
@@ -268,3 +289,15 @@ class ContactRole(models.Model):
     kind = ChoiceArrayField(models.CharField(max_length=4, choices=ROLE_KINDS))
     date_from = models.DateField()
     date_until = models.DateField()
+
+    def __str__(self):
+        return '%s, %s for %s' % (self.contact, self.get_kind_display, self.organization)
+
+    @property
+    def get_kind_display(self):
+        """
+        Due to a lack of support to use get_FOO_display in a ArrayField, one has to create
+        one 'manually'.
+        """
+        choices = dict(ROLE_KINDS)
+        return ', '.join([choices[value] for index, value in enumerate(self.kind)])
diff --git a/organizations/templates/organizations/_organization_card.html b/organizations/templates/organizations/_organization_card.html
index 8986814da202aba702763e6cc1a5582117b97f93..1f85d191c4bf62c6e53953b5d6ef107f4b5aa9e4 100644
--- a/organizations/templates/organizations/_organization_card.html
+++ b/organizations/templates/organizations/_organization_card.html
@@ -1,5 +1,5 @@
 {% load bootstrap %}
-
+{% load guardian_tags %}
 {% load user_groups %}
 {% load organizations_extras %}
 
@@ -15,6 +15,8 @@ $(document).ready(function($) {
 
 {% is_scipost_admin request.user as is_scipost_admin %}
 
+{% get_obj_perms request.user for org as "user_org_perms" %}
+
 <div class="card-body">
 
   <div class="row">
@@ -24,7 +26,8 @@ $(document).ready(function($) {
 	  <a class="nav-link" id="details-{{ org.id }}-tab" data-toggle="tab" href="#details-{{ org.id }}" role="tab" aria-controls="details-{{ org.id }}" aria-selected="true">Details</a>
 	</li>
 	<li class="nav-item">
-	  <a class="nav-link active" id="publications-{{ org.id }}-tab" data-toggle="tab" href="#publications-{{ org.id }}" role="tab" aria-controls="publications-{{ org.id }}" aria-selected="true">Publications{% if is_scipost_admin %} & PubFractions{% endif %}</a>
+	  <a class="nav-link active" id="publications-{{ org.id }}-tab" data-toggle="tab" href="#publications-{{ org.id }}" role="tab" aria-controls="publications-{{ org.id }}" aria-selected="true">Publications{% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+ & PubFractions{% endif %}</a>
 	</li>
 	<li class="nav-item">
 	  <a class="nav-link" id="authors-{{ org.id }}-tab" data-toggle="tab" href="#authors-{{ org.id }}" role="tab" aria-controls="authors-{{ org.id }}" aria-selected="true">Associated Authors</a>
@@ -35,30 +38,40 @@ $(document).ready(function($) {
 	<li class="nav-item">
 	  <a class="nav-link" id="support-{{ org.id }}-tab" data-toggle="tab" href="#support-{{ org.id }}" role="tab" aria-controls="support-{{ org.id }}" aria-selected="true">Support history</a>
 	</li>
-	{% if perms.scipost.can_manage_organizations %}
+	{% if perms.scipost.can_manage_organizations or perms.scipost.can_add_contactperson %}
 	<li class="nav-item">
 	  <a class="nav-link" id="contacts-{{ org.id }}-tab" data-toggle="tab" href="#contacts-{{ org.id }}" role="tab" aria-controls="contacts-{{ org.id }}" aria-selected="true">Contacts</a>
 	</li>
+	{% endif %}
+	{% if perms.scipost.can_manage_organizations %}
 	<li class="nav-item">
 	  <a class="nav-link" id="events-{{ org.id }}-tab" data-toggle="tab" href="#events-{{ org.id }}" role="tab" aria-controls="events-{{ org.id }}" aria-selected="true">Events</a>
 	</li>
-	<li class="nav-item">
-	  <a class="nav-link" id="manage-{{ org.id }}-tab" data-toggle="tab" href="#manage-{{ org.id }}" role="tab" aria-controls="manage-{{ org.id }}" aria-selected="true">Manage</a>
-	</li>
 	{% endif %}
       </ul>
 
       <div class="tab-content" id="organization-{{ org.id }}-tab">
 
 	<div class="tab-pane pt-4" id="details-{{ org.id }}" role="tabpanel" aria-labelledby="details-{{ org.id }}-tab">
+	  {% if perms.scipost.can_manage_organizations %}
+	  <h3>Manage this organization:</h3>
+	  <ul>
+	    <li><a href="{% url 'organizations:organization_update' pk=org.id %}">Update</a></li>
+	    <li><a href="{% url 'organizations:organization_delete' pk=org.id %}">Delete</a></li>
+	  </ul>
+	  <hr/>
+	  {% endif %}
+
 	  <h3>Details:</h3>
 	  {% include 'organizations/_organization_details_contents.html' with org=org %}
 	</div>
 
 	<div class="tab-pane show active pt-4" id="publications-{{ org.id }}" role="tabpanel" aria-labelledby="publications-{{ org.id }}-tab">
-	  <h3>Publications associated to this Organization{% if is_scipost_admin %} <span class="text-muted small">(with total PubFractions <i class="fa fa-info-circle" data-toggle="tooltip" data-html="true" title="" data-original-title="Fraction of a publication's funding/institutional support associated to a given Organization"></i>)</span>{% endif %}:</h3>
+	  <h3>Publications associated to this Organization{% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+ <span class="text-muted small">(with total PubFractions <i class="fa fa-info-circle" data-toggle="tooltip" data-html="true" title="" data-original-title="Fraction of a publication's funding/institutional support associated to a given Organization"></i>)</span>{% endif %}:</h3>
 	  {% for pubyear in pubyears %}
-	  <h4>{{ pubyear }}{% if is_scipost_admin %} <span class="text-muted small">(total pubfractions: {{ org|pubfractions_in_year:pubyear }})</span>{% endif %}</h4>
+	  <h4>{{ pubyear }}{% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+ <span class="text-muted small">(total pubfractions: {{ org|pubfractions_in_year:pubyear }})</span>{% endif %}</h4>
 	  <ul>
 	    {% for publication in org.get_publications %}
 	    {% if publication.publication_date|date:'Y'|add:"0" == pubyear %}
@@ -66,7 +79,7 @@ $(document).ready(function($) {
               <a href="{{ publication.get_absolute_url }}">{{ publication.title }}</a>
               <br>by {{ publication.author_list }},
               <br>{{ publication.citation }}
-	      {% if is_scipost_admin %}
+	      {% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
 	      <br><span class="text-muted small">Pubfraction: {{ org|pubfraction_for_publication:publication }}</span>
 	      {% endif %}
 	    </li>
@@ -150,76 +163,95 @@ $(document).ready(function($) {
 	  {% else %}
 	  <p><strong>This Organization has <span class="text-danger">not yet</span> supported SciPost.</strong></p>
 	  {% endif %}
-
-	  {% if is_scipost_admin %}
-	  <h3 class="text-danger">To be removed (Admin view only):</h3>
-	  <h3>Supporting Partner Agreements history:</h3>
-	  {% with agreement=org.partner.get_latest_active_agreement %}
-	  {% if agreement %}
-	  <p>This organization is currently a SciPost Supporting Partner.</p>
-	  {% endif %}
-	  {% endwith %}
-	  {% if org.partner.agreements %}
-	  <table class="table">
-	    <thead>
-	      <th>Status</th>
-	      <th>Duration</th>
-	      <th>Start date</th>
-	      <th>Contribution/year</th>
-	    </thead>
-	    <tbody>
-	      {% for agreement in org.partner.agreements.all %}
-	      <tr>
-		<td>{{ agreement.get_status_display }}</td>
-		<td>{{ agreement.get_duration_display }}</td>
-		<td>{{ agreement.start_date }}</td>
-		<td>&euro;{{ agreement.offered_yearly_contribution }}</td>
-	      </tr>
-	      {% endfor %}
-	      <tr style="border-top: 2px solid black">
-		<td colspan="2"></td><td>Total contribution obtained:</td><td>&euro; {{ org.get_total_contribution_obtained }}</td></tr>
-	    </tbody>
-	  </table>
-	  {% else %}
-	  <p>This organization has <span class="text-danger">not yet</span> been a SciPost Supporting Partner.</p>
-	  {% endif %}
 	</div>
-	{% endif %}
 
+	{% if perms.scipost.can_manage_organizations or perms.scipost.can_add_contactperson or "can_view_org_contacts" in user_org_perms %}
 	<div class="tab-pane pt-4" id="contacts-{{ org.id }}" role="tabpanel" aria-labelledby="contacts-{{ org.id }}-tab">
-	  {% if perms.scipost.can_manage_organizations %}
 	  <h3>Contacts (with explicit role)</h3>
+	  {% if perms.scipost.can_manage_organizations %}
+	  <ul>
+	    <li><a href="{% url 'organizations:add_contact' organization_id=org.id %}">Add a new Contact</a></li>
+	  </ul>
+	  {% endif %}
 	  <table class="table">
+	    <tr>
+	      <th>Name</th>
+	      <th>Kind</th>
+	      <th>Date from</th>
+	      <th>Date until</th>
+	      {% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+	      <th>Account<br/>active?</th>
+	      <th>Actions</th>
+	      {% endif %}
+	    </tr>
 	    {% for contactrole in org.contactrole_set.all %}
 	    <tr>
 	      <td>{{ contactrole.contact }}</td>
 	      <td>{{ contactrole.get_kind_display }}</td>
 	      <td>{{ contactrole.date_from|date:"Y-m-d" }}</td>
 	      <td>{{ contactrole.date_until|date:"Y-m-d" }}</td>
+	      {% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+	      <td>{% if contactrole.contact.user.is_active %}<i class="fa fa-check-circle text-success"></i>{% else %}<i class="fa fa-times-circle text-danger"></i>{% endif %}</td>
+	      <td>
+		<ul class="list-unstyled">
+		  {% if perms.scipost.can_manage_organizations %}
+		  <li><a href="{% url 'organizations:email_contactrole' contactrole_id=contactrole.id %}">Email (generic)</a></li>
+		  <li><a href="{% url 'organizations:email_contactrole' contactrole_id=contactrole.id mail='renewal' %}">Email (subsidy renewal)</a></li>
+		  {% endif %}
+		  {% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+		  <li><a href="{% url 'organizations:contactrole_update' pk=contactrole.id %}"><span class="text-warning">Update</span></a></li>
+		  {% endif %}
+		  {% if perms.scipost.can_manage_organizations %}
+		  <li><a href="{% url 'organizations:contactrole_delete' pk=contactrole.id %}"><span class="text-danger">Delete</span></a></li>
+		  {% endif %}
+		</ul>
+	      </td>
+	      {% endif %}
 	    </tr>
 	    {% endfor %}
 	  </table>
 
 	  <h3>Contact persons</h3>
+	  {% if perms.scipost.can_manage_organizations or perms.scipost.can_add_contactperson %}
+	  <ul>
+	    <li><a href="{% url 'organizations:contactperson_create' organization_id=org.id %}">Add/suggest a contact person for this Organization</a></li>
+	  </ul>
+	  {% endif %}
 	  <table class="table">
-	    {% for contact in org.contactperson_set.all %}
+	    {% for contactperson in org.contactperson_set.all %}
 	    <tr>
-	      <td>{{ contact }}</td>
-	      <td>{{ contact.email }}</td>
-	      <td>{{ contact.role }}</td>
+	      <td>{{ contactperson }}</td>
+	      <td>{{ contactperson.email }}</td>
+	      <td>{{ contactperson.role }}</td>
+	      {% if perms.scipost.can_manage_organizations or "can_view_org_contacts" in user_org_perms %}
+	      <td>
+		<ul class="list-unstyled">
+		  {% if perms.scipost.can_manage_organizations %}
+		  <li><a href="{% url 'organizations:email_contactperson' contactperson_id=contactperson.id %}">Email (initial)</a></li>
+		  <li><a href="{% url 'organizations:email_contactperson' contactperson_id=contactperson.id mail='followup' %}">Email (followup)</a></li>
+		  <li><a href="{% url 'organizations:add_contact' organization_id=org.id contactperson_id=contactperson.id %}"><span class="text-success">Upgrade to Contact</span></a></li>
+		  {% endif %}
+		  <li><a href="{% url 'organizations:contactperson_update' pk=contactperson.id %}"><span class="text-warning">Update</span></a></li>
+		  <li><a href="{% url 'organizations:contactperson_delete' pk=contactperson.id %}"><span class="text-danger">Delete</span></a></li>
+		</ul>
+	      </td>
+	      {% endif %}
 	    </tr>
 	    {% empty %}
 	    <tr>
-	      <td>>No contact person defined</td>
+	      <td>No contact person defined</td>
 	    </tr>
 	    {% endfor %}
 	  </table>
-	  {% endif %}
 	</div>
+	{% endif %}
 
+	{% if perms.scipost.can_manage_organizations %}
 	<div class="tab-pane pt-4" id="events-{{ org.id }}" role="tabpanel" aria-labelledby="events-{{ org.id }}-tab">
-	  {% if perms.scipost.can_manage_organizations %}
 	  <h3>Events</h3>
+	  <ul>
+	    <li><a href="{% url 'organizations:organizationevent_create' pk=org.id %}">Add an event</a></li>
+	  </ul>
 	  <ul>
 	    {% for event in org.organizationevent_set.all %}
 	    {% include 'organizations/_organization_event_li.html' with event=event %}
@@ -227,19 +259,9 @@ $(document).ready(function($) {
 	    <li>No event found</li>
 	    {% endfor %}
 	  </ul>
-	  {% endif %}
 	</div>
+	{% endif %}
 
-	<div class="tab-pane pt-4" id="manage-{{ org.id }}" role="tabpanel" aria-labelledby="manage-{{ org.id }}-tab">
-	  {% if perms.scipost.can_manage_organizations %}
-	  <h3>Manage this organization:</h3>
-	  <ul>
-	    <li><a href="{% url 'organizations:organization_update' pk=org.id %}">Update</a></li>
-	    <li><a href="{% url 'organizations:organization_delete' pk=org.id %}">Delete</a></li>
-	  </ul>
-	  <hr/>
-	  {% endif %}
-	</div>
       </div>
     </div>
   </div>
diff --git a/organizations/templates/organizations/activate_account.html b/organizations/templates/organizations/activate_account.html
new file mode 100644
index 0000000000000000000000000000000000000000..aa948a06064755e8b0856c5de239e47ed08732b4
--- /dev/null
+++ b/organizations/templates/organizations/activate_account.html
@@ -0,0 +1,27 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block pagetitle %}{{block.super}} Activate Account{% endblock pagetitle %}
+
+{% block content %}
+
+<h1 class="highlight">Activate Account</h1>
+<div class="row justify-content-center">
+    <div class="col-md-8">
+        <h2>{{ contact.get_title_display }} {{ contact.user.first_name }} {{ contact.user.last_name }}</h2>
+        <h3>{{ contact.user.email }}</h3>
+    </div>
+</div>
+
+<div class="row justify-content-center">
+    <div class="col-md-8 mb-5">
+      <form method="post">
+        {% csrf_token %}
+        {{ form|bootstrap }}
+        <input class="btn btn-primary" type="submit" value="Activate"/>
+      </form>
+    </div>
+</div>
+
+{% endblock content %}
diff --git a/organizations/templates/organizations/contactperson_confirm_delete.html b/organizations/templates/organizations/contactperson_confirm_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..7f1d9fa121869dc33c2eb27baea62a79c6f9ac5d
--- /dev/null
+++ b/organizations/templates/organizations/contactperson_confirm_delete.html
@@ -0,0 +1,30 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'organizations:organizations' %}">Organizations</a></span>
+<span class="breadcrumb-item">Confirm deletetion</span>
+{% endblock %}
+
+{% block pagetitle %}: Delete Contact Person{% endblock pagetitle %}
+
+{% block content %}
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Delete Contact Person</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 Contact Person?</h3>
+      <input type="submit" class="btn btn-danger" value="Yes, delete it" />
+    </form>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/organizations/templates/organizations/contactperson_form.html b/organizations/templates/organizations/contactperson_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..381d45694a77df9111fb8780c0dae88e1486c279
--- /dev/null
+++ b/organizations/templates/organizations/contactperson_form.html
@@ -0,0 +1,23 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'organizations:organizations' %}">Organizations</a></span>
+<span class="breadcrumb-item">{% if form.instance.id %}Update {{ form.instance }}{% else %}Add new Contact Person{% endif %}</span>
+{% endblock %}
+
+{% block pagetitle %}: Contact Person{% endblock pagetitle %}
+
+
+{% block content %}
+<div class="row">
+  <div class="col-12">
+    <form action="" method="post">
+      {% csrf_token %}
+      {{ form|bootstrap }}
+      <input type="submit" value="Submit" class="btn btn-primary">
+  </div>
+</div>
+{% endblock content %}
diff --git a/organizations/templates/organizations/contactperson_list.html b/organizations/templates/organizations/contactperson_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..4267de192c21c66433bd5c2196b5f628817eb656
--- /dev/null
+++ b/organizations/templates/organizations/contactperson_list.html
@@ -0,0 +1,49 @@
+{% extends 'organizations/base.html' %}
+
+{% block pagetitle %}: Contact Persons{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item">Contact Persons</span>
+{% endblock %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+    <h3 class="highlight">Contact Persons</h3>
+    <p>Contact Persons are by definition employees of an Organization, who play a role of potential relevance to SciPost's sponsoring efforts. SciPost Admin takes charge of contacting Contact Persons listed here, to try to promote them to registered Contacts (members of the Sponsors Board).</p>
+    <p>Do you people who you think should appear on this list?</p>
+    <p>Are they not in our list of registered Contacts (which you can view on your <a href="{% url 'organizations:dashboard' %}" target="_blank">dashboard</a> under the Sponsors Board tab)?</p>
+    <p>Then please help us out: <a href="{% url 'organizations:contactperson_create' %}">add a Contact Person</a> instance.</p>
+
+    <table class="table">
+      <thead class="thead-default">
+	<tr>
+	  <td>Name</td>
+	  <td>Organization</td>
+	  <td>Role</td>
+	  <td>Actions</td>
+	</tr>
+      </thead>
+      <tbody>
+	{% for cp in object_list %}
+	<tr>
+	  <td>{{ cp.last_name }}, {{ cp.get_title_display }} {{ cp.first_name }}</td>
+	  <td><a href="{{ cp.organization.get_absolute_url }}">{{ cp.organization }}</a></td>
+	  <td>{{ cp.role }}</td>
+	  <td>
+	    <ul class="list-unstyled">
+	      <li><a href="{% url 'organizations:contactperson_update' pk=cp.id %}"><span class="text-warning">Update</span></a></li>
+	    </ul>
+	  </td>
+	</tr>
+	{% endfor %}
+      </tbody>
+    </table>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/organizations/templates/organizations/contactrole_confirm_delete.html b/organizations/templates/organizations/contactrole_confirm_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..f0d3ccfbc02ab888d393c54bb93144ced7e8bf39
--- /dev/null
+++ b/organizations/templates/organizations/contactrole_confirm_delete.html
@@ -0,0 +1,30 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'organizations:organizations' %}">Organizations</a></span>
+<span class="breadcrumb-item">Confirm deletetion</span>
+{% endblock %}
+
+{% block pagetitle %}: Delete ContactRole{% endblock pagetitle %}
+
+{% block content %}
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Delete ContactRole</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 ContactRole?</h3>
+      <input type="submit" class="btn btn-danger" value="Yes, delete it" />
+    </form>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/organizations/templates/organizations/contactrole_form.html b/organizations/templates/organizations/contactrole_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..211764a47a2a367cf71f2e1bd0e3c63bcae587ae
--- /dev/null
+++ b/organizations/templates/organizations/contactrole_form.html
@@ -0,0 +1,28 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'organizations:organizations' %}">Organizations</a></span>
+<span class="breadcrumb-item">{% if form.instance.id %}Update {{ form.instance }}{% else %}Add new ContactRole{% endif %}</span>
+{% endblock %}
+
+{% block pagetitle %}: ContactRole{% endblock pagetitle %}
+
+
+{% block content %}
+<div class="row">
+  <div class="col-12">
+    <form action="" method="post">
+      {% csrf_token %}
+      {{ form|bootstrap }}
+      <input type="submit" value="Submit" class="btn btn-primary">
+  </div>
+</div>
+{% endblock content %}
+
+{% block footer_script %}
+{{ block.super }}
+{{ form.media }}
+{% endblock footer_script %}
diff --git a/organizations/templates/organizations/dashboard.html b/organizations/templates/organizations/dashboard.html
new file mode 100644
index 0000000000000000000000000000000000000000..002c8ce725edf1d1fe8eeb64d1448139fae3c40b
--- /dev/null
+++ b/organizations/templates/organizations/dashboard.html
@@ -0,0 +1,217 @@
+{% extends 'organizations/base.html' %}
+
+{% load bootstrap %}
+
+{% block pagetitle %}: organizations dashboard{% endblock pagetitle %}
+
+{% block headsup %}
+<script type="text/javascript">
+$(document).ready(function($) {
+    $(".table-row").click(function() {
+        window.document.location = $(this).data("href");
+    });
+});
+</script>
+{% endblock headsup %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+    {% if request.user.org_contact %}
+    <h1 class="highlight">Welcome to your Organizations dashboard, {{ request.user.org_contact.get_title_display }} {{ request.user.last_name }}</h1>
+    {% elif perms.scipost.can_manage_organizations %}
+    <h1 class="highlight">Organizations dashboard</h1>
+    {% endif %}
+  </div>
+</div>
+
+<div class="row">
+  <div class="col-12">
+    <div class="tab-nav-container">
+      <div class="tab-nav-inner">
+	<ul class="nav btn-group personal-page-nav" role="tablist">
+	  {% if request.user.org_contact %}
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="#account" class="nav-link" data-toggle="tab">Account</a>
+	  </li>
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="#own_roles" class="nav-link active" data-toggle="tab">Your roles</a>
+	  </li>
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="#subsidies" class="nav-link" data-toggle="tab">Subsidies<br/><span class="small text-muted">[from your Orgs]</span></a>
+	  </li>
+	  {% endif %}
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="{% url 'finances:subsidies' %}" class="nav-link" target="_blank">Subsidies<br/><span class="small text-muted">[full list]</span></a>
+	  </li>
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="#board" class="nav-link" data-toggle="tab">Sponsors Board<br/><span class="small text-muted">[registered Contacts]</span></a>
+	  </li>
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="{% url 'organizations:contactperson_list' %}" class="nav-link" target="_blank">Contact Persons<br/><span class="small text-muted">[unregistered contacts]</span></a>
+	  </li>
+	  {% if perms.scipost.can_manage_organizations %}
+	  <li class="nav-item btn btn-outline-secondary">
+	    <a href="{% url 'organizations:organizationevent_list' %}" class="nav-link" target="_blank">Events</a>
+	  </li>
+	  {% endif %}
+	</ul>
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="tab-content">
+
+  <div class="tab-pane" id="account" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+	<h2 class="highlight">Your account</h2>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-12">
+	<p>{{ request.user.org_contact }}</p>
+
+        <h3>Update your personal data or password</h3>
+        <ul>
+          <li><a href="{% url 'scipost:update_personal_data' %}">Update your personal data</a></li>
+          <li><a href="{% url 'scipost:change_password' %}">Change your password</a></li>
+        </ul>
+
+      </div>
+    </div>
+  </div>
+
+  <div class="tab-pane{% if request.user.org_contact %} active{% endif %}" id="own_roles" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+	<h2 class="highlight">Your Organizations-related roles</h2>
+	<p>Click on an Organization's name to see its details.</p>
+	<table class="table">
+	  <tr>
+	    <th>Organization</th>
+	    <th>Role kind</th>
+	    <th>Date from</th>
+	    <th>Date until</th>
+	    <th>Actions</th>
+	  </tr>
+	  {% for role in own_roles %}
+	  <tr>
+	    <td><a href="{{ role.organization.get_absolute_url }}">{{ role.organization }}</a></td>
+	    <td>{{ role.get_kind_display }}</td>
+	    <td>{{ role.date_from|date:"Y-m-d" }}</td>
+	    <td>{{ role.date_until|date:"Y-m-d" }}</td>
+	    <td><a href="{% url 'organizations:contactrole_update' pk=role.id %}"><span class="text-warning">Update</span></a></td>
+	  </tr>
+	  {% empty %}
+	  <tr>
+	    <td>No role has been defined</td>
+	  </tr>
+	  {% endfor %}
+	</table>
+      </div>
+    </div>
+  </div>
+
+  <div class="tab-pane" id="subsidies" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+	<h2 class="highlight">Subsidies from your Organizations</h2>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-12">
+	<ul>
+	  {% for role in request.user.org_contact.roles.all %}
+	  <li>
+	    <h4>{{ role.organization }}</h4>
+
+	    {% if role.organization.subsidy_set.all|length > 0 %}
+	    <p>List of the subsidies (in one form or another) which SciPost has received from this Organization. Click on a row to see more details.</p>
+	    <table class="table table-hover mb-5">
+	      <thead class="thead-default">
+		<tr>
+		  <th>Type</th>
+		  <th>Amount</th>
+		  <th>Date</th>
+		</tr>
+	      </thead>
+	      <tbody>
+		{% for subsidy in role.organization.subsidy_set.all %}
+		<tr class="table-row" data-href="{% url 'finances:subsidy_details' pk=subsidy.id %}" style="cursor: pointer;">
+		  <td>{{ subsidy.get_subsidy_type_display }}</td>
+		  <td>&euro;{{ subsidy.amount }}</td>
+		  <td>{{ subsidy.date }}{% if subsidy.date_until %} until {{ subsidy.date_until }}{% endif %}</td>
+		</tr>
+		{% endfor %}
+		<tr style="border-top: 2px solid black">
+		  <td>Total support obtained:</td>
+		  <td>&euro;{{ role.organization.get_total_subsidies_obtained }}</td>
+		  <td colspan="2">
+		</tr>
+	      </tbody>
+	    </table>
+	    {% else %}
+	    <p><strong>This Organization has <span class="text-danger">not yet</span> supported SciPost.</strong></p>
+	    {% endif %}
+	  </li>
+	  {% empty %}
+	  <li>No Organization found</li>
+	  {% endfor %}
+	</ul>
+      </div>
+    </div>
+  </div>
+
+  <div class="tab-pane" id="board" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+	<h2 class="highlight">Sponsors Board</h2>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-12">
+	<p>The Sponsors Board is composed of all registered Organization Contacts.</p>
+	<p>Do you know people who you think should appear on this list? Help us by checking if they are already on our <a href="{% url 'organizations:contactperson_list' %}" target="_blank">list of Contact Persons</a>, and if not, please add them!</p>
+        <h3>Active Contacts</h3>
+	<table class="table">
+	  <thead class="thead-default">
+	    <tr>
+	      <th>Name</th>
+	      <th>Organization(s) / role(s)</th>
+	      {% if perms.scipost.can_manage_organizations %}
+	      <th>Account<br/>active?</th>
+	      {% endif %}
+	    </tr>
+	  </thead>
+	  <tbody>
+	    {% for contact in contacts %}
+	    <tr>
+	      <td>{{ contact }}</td>
+	      <td>
+		<ul class="list-group list-group-flush">
+		  {% for role in contact.roles.all %}
+		  <li class="list-group-item"><a href="{{ role.organization.get_absolute_url }}" target="_blank">{{ role.organization }}</a> / {{ role.get_kind_display }}</li>
+		  {% empty %}
+		  <li class="list-group-item">No Organization found</li>
+		  {% endfor %}
+		</ul>
+	      </td>
+	      {% if perms.scipost.can_manage_organizations %}
+	      <td>{% if contact.user.is_active %}<i class="fa fa-check-circle text-success"></i>{% else %}<i class="fa fa-times-circle text-danger"></i>{% endif %}</td>
+	      {% endif %}
+	    </tr>
+	    {% empty %}
+	    <tr><td>No contact found</td></tr>
+	    {% endfor %}
+	  </tbody>
+	</table>
+      </div>
+    </div>
+  </div>
+
+</div>
+
+{% endblock content %}
diff --git a/organizations/templates/organizations/organization_add_contact.html b/organizations/templates/organizations/organization_add_contact.html
new file mode 100644
index 0000000000000000000000000000000000000000..061b24c322ff8f7a29549585d3b227c0dd0ea22b
--- /dev/null
+++ b/organizations/templates/organizations/organization_add_contact.html
@@ -0,0 +1,33 @@
+{% extends 'scipost/base.html' %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <span class="breadcrumb-item">Add Contact</span>
+{% endblock %}
+
+{% block pagetitle %}{{block.super}} Add Contact{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Add Contact for Organization {{ organization }}</h1>
+    </div>
+</div>
+
+<div class="row">
+    <div class="col-12">
+      <form method="post">
+        {% csrf_token %}
+        <div class="mb-5">
+            {{ form|bootstrap }}
+        </div>
+
+        <input class="btn btn-primary" type="submit" value="Submit"/>
+      </form>
+    </div>
+</div>
+
+{% endblock content %}
diff --git a/organizations/templates/organizations/organization_list.html b/organizations/templates/organizations/organization_list.html
index f238fc47ced5cda85a857bd583abb7d0627977c8..f67cd4f7388221b7cc5e829614ac60c274c2dd9f 100644
--- a/organizations/templates/organizations/organization_list.html
+++ b/organizations/templates/organizations/organization_list.html
@@ -4,7 +4,9 @@
 
 {% load staticfiles %}
 {% load user_groups %}
+{% load add_get_parameters %}
 {% load organizations_extras %}
+{% load countries %}
 
 {% is_scipost_admin request.user as is_scipost_admin %}
 
@@ -16,6 +18,7 @@ $(document).ready(function($) {
     });
 });
 </script>
+<link rel="stylesheet" href="{% static 'flags/sprite-hq.css' %}">
 {% endblock headsup %}
 
 {% block breadcrumb_items %}
@@ -30,6 +33,7 @@ $(document).ready(function($) {
     {% if perms.scipost.can_manage_organizations %}
     <h3>Management actions:</h3>
     <ul>
+      <li><a href="{% url 'organizations:dashboard' %}">Go to the dashboard</a></li>
       <li><a href="{% url 'organizations:organization_create' %}">Create a new Organization instance</a></li>
       <li><a href="{% url 'funders:funders_dashboard' %}">Link Funders to Organizations</a> ({{ nr_funders_wo_organization }} found in need of linking)</li>
       <li><a href="{% url 'partners:prospartner_link_organization' %}">Link ProspectivePartners to Organizations</a> ({{ nr_prospartners_wo_organization }} found in need of linking)</li>
@@ -66,21 +70,38 @@ $(document).ready(function($) {
   </div>
 </div>
 
+<div class="row">
+  <div class="col-3">
+    <h3>Click on flag to view by Country</h3>
+    <p><a href="{% url 'organizations:organizations' %}">View all</a></p>
+  </div>
+  <div class="col-8">
+    <ul>
+      {% for code in countrycodes %}
+      {% get_country code as country_obj %}
+      <li style="display: inline-block;">
+	<a href="{% add_get_parameters country=code %}"><i class="{{ country_obj.flag_css }}" aria-label="{{ country_obj.code }}" data-toggle="tooltip" title="{{ country_obj.name }}"></i></a>
+      </li>
+      {% endfor %}
+    </ul>
+  </div>
+</div>
+
 <div class="row">
   <div class="col-12">
     <table class="table table-hover mb-5">
       <thead class="thead-default">
 	<tr>
-	  <th><a href="?order_by=country">Country</a></th>
-	  <th><a href="?order_by=name">Name</a>&nbsp;&nbsp;<small>[acronym]</small></th>
+	  <th><a href="{% add_get_parameters order_by='country' %}">Country</a></th>
+	  <th><a href="{% add_get_parameters order_by='name' %}">Name</a>&nbsp;&nbsp;<small>[acronym]</small></th>
 	  <th>NAP <i class="fa fa-info-circle" data-toggle="tooltip" data-html="true" title="" data-original-title="Number of associated publications<br/>For details, click on the Organization and consult the Associated Publications tab"></i>
 	    {% if request.GET.ordering != 'asc' %}
-	    <a href="?order_by=nap&ordering=asc"><i class="fa fa-sort-asc"></i></a>
+	    <a href="{% add_get_parameters order_by='nap' ordering='asc' %}"><i class="fa fa-sort-asc"></i></a>
 	    {% else %}
 	    <a href="{% url 'organizations:organizations' %}"><i class="fa fa-sort-asc"></i></a>
 	    {% endif %}
 	    {% if request.GET.ordering != 'desc' %}
-	    <a href="?order_by=nap&ordering=desc"><i class="fa fa-sort-desc"></i></a>
+	    <a href="{% add_get_parameters order_by='nap' ordering='desc' %}"><i class="fa fa-sort-desc"></i></a>
 	    {% else %}
 	    <a href="{% url 'organizations:organizations' %}"><i class="fa fa-sort-desc"></i></a>
 	    {% endif %}
@@ -125,6 +146,13 @@ $(document).ready(function($) {
 	{% endfor %}
       </tbody>
     </table>
+
+    {% if is_paginated %}
+    <div class="col-12">
+      {% include 'partials/pagination.html' with page_obj=page_obj %}
+    </div>
+    {% endif %}
+
   </div>
 </div>
 
diff --git a/organizations/templates/organizations/organizationevent_form.html b/organizations/templates/organizations/organizationevent_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..d100a520fa441fba12fcf9fb7ce9bf591d547ff9
--- /dev/null
+++ b/organizations/templates/organizations/organizationevent_form.html
@@ -0,0 +1,28 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item"><a href="{% url 'organizations:organizations' %}">Organizations</a></span>
+<span class="breadcrumb-item">{% if form.instance.id %}Update {{ form.instance }}{% else %}Add new OrganizationEvent{% endif %}</span>
+{% endblock %}
+
+{% block pagetitle %}: OrganizationEvent{% endblock pagetitle %}
+
+
+{% block content %}
+<div class="row">
+  <div class="col-12">
+    <form action="" method="post">
+      {% csrf_token %}
+      {{ form|bootstrap }}
+      <input type="submit" value="Submit" class="btn btn-primary">
+  </div>
+</div>
+{% endblock content %}
+
+{% block footer_script %}
+{{ block.super }}
+{{ form.media }}
+{% endblock footer_script %}
diff --git a/organizations/templates/organizations/organizationevent_list.html b/organizations/templates/organizations/organizationevent_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..85610bef6f2ae3aa5b67bd19e66f393f56eb3657
--- /dev/null
+++ b/organizations/templates/organizations/organizationevent_list.html
@@ -0,0 +1,50 @@
+{% extends 'organizations/base.html' %}
+
+{% block pagetitle %}: Organization Events{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+{{ block.super }}
+<span class="breadcrumb-item">Organization Events</span>
+{% endblock %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+    <h3 class="highlight">Organization Events</h3>
+
+    <table class="table">
+      <thead class="thead-default">
+	<tr>
+	  <th>Organization</th>
+	  <th>Event</th>
+	  <th>Comments</th>
+	  <th>Noted on</th>
+	  <th>Noted by</th>
+	</tr>
+      </thead>
+      <tbody>
+	{% for event in object_list %}
+	<tr>
+	  <td><a href="{% url 'organizations:organization_details' pk=event.organization.id %}">{{ event.organization }}</a></td>
+	  <td>{{ event.get_event_display }}</td>
+	  <td>{{ event.comments|linebreaks }}</td>
+	  <td>{{ event.noted_on }}</td>
+	  <td>{{ event.noted_by }}</td>
+	</tr>
+	{% endfor %}
+      </tbody>
+    </table>
+
+    {% if is_paginated %}
+    <div class="col-12">
+      {% include 'partials/pagination.html' with page_obj=page_obj %}
+    </div>
+    {% endif %}
+
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/organizations/urls.py b/organizations/urls.py
index 5ad00b7c7a45ae2669a3ec20f83af4aec4bc9264..d12d9d3a45c4f3f508735df89831908fad52c0ab 100644
--- a/organizations/urls.py
+++ b/organizations/urls.py
@@ -32,4 +32,90 @@ urlpatterns = [
         views.OrganizationDetailView.as_view(),
         name='organization_details'
     ),
+    url(
+        r'^(?P<pk>[0-9]+)/orgevent/add/$',
+        views.OrganizationEventCreateView.as_view(),
+        name='organizationevent_create'
+    ),
+    url(
+        r'^organizationevents/$',
+        views.OrganizationEventListView.as_view(),
+        name='organizationevent_list'
+    ),
+    url(
+        r'^add_contactperson/(?P<organization_id>[0-9]+)/$',
+        views.ContactPersonCreateView.as_view(),
+        name='contactperson_create'
+    ),
+    url(
+        r'^contactperson/add/$',
+        views.ContactPersonCreateView.as_view(),
+        name='contactperson_create'
+    ),
+    url(
+        r'^contactperson/(?P<pk>[0-9]+)/update/$',
+        views.ContactPersonUpdateView.as_view(),
+        name='contactperson_update'
+    ),
+    url(
+        r'^contactperson/(?P<pk>[0-9]+)/delete/$',
+        views.ContactPersonDeleteView.as_view(),
+        name='contactperson_delete'
+    ),
+    url(
+        r'^contactpersons/$',
+        views.ContactPersonListView.as_view(),
+        name='contactperson_list'
+    ),
+    url(
+        r'^contactperson/(?P<contactperson_id>[0-9]+)/email/(?P<mail>followup)$',
+        views.email_contactperson,
+        name='email_contactperson'
+    ),
+    url(
+        r'^contactperson/(?P<contactperson_id>[0-9]+)/email/$',
+        views.email_contactperson,
+        name='email_contactperson'
+    ),
+    url(
+        # For upgrading a ContactPerson to a Contact
+        r'^add_contact/(?P<organization_id>[0-9]+)/(?P<contactperson_id>[0-9]+)/$',
+        views.organization_add_contact,
+        name='add_contact'
+    ),
+    url(
+        r'^add_contact/(?P<organization_id>[0-9]+)/$',
+        views.organization_add_contact,
+        name='add_contact'
+    ),
+    url(
+        r'^activate/(?P<activation_key>.+)$',
+        views.activate_account,
+        name='activate_account'
+    ),
+    url(
+        r'^dashboard/$',
+        views.dashboard,
+        name='dashboard'
+    ),
+    url(
+        r'^contactrole/(?P<pk>[0-9]+)/update/$',
+        views.ContactRoleUpdateView.as_view(),
+        name='contactrole_update'
+    ),
+    url(
+        r'^contactrole/(?P<pk>[0-9]+)/delete/$',
+        views.ContactRoleDeleteView.as_view(),
+        name='contactrole_delete'
+    ),
+    url(
+        r'^contactrole/(?P<contactrole_id>[0-9]+)/email/(?P<mail>renewal)$',
+        views.email_contactrole,
+        name='email_contactrole'
+    ),
+    url(
+        r'^contactrole/(?P<contactrole_id>[0-9]+)/email/$',
+        views.email_contactrole,
+        name='email_contactrole'
+    ),
 ]
diff --git a/organizations/views.py b/organizations/views.py
index 7ad4bd0070b0b5d33d948f7802d5e4ca3f0ee65f..d9508050768f7dbbe10cb571a367ae66bce03a72 100644
--- a/organizations/views.py
+++ b/organizations/views.py
@@ -2,19 +2,33 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.mixins import UserPassesTestMixin
+from django.core.exceptions import PermissionDenied
 from django.core.urlresolvers import reverse_lazy
+from django.db import transaction
+from django.shortcuts import get_object_or_404, render, reverse, redirect
 from django.utils import timezone
 from django.views.generic.detail import DetailView
 from django.views.generic.edit import CreateView, UpdateView, DeleteView
 from django.views.generic.list import ListView
 
-from .constants import ORGTYPE_PRIVATE_BENEFACTOR
-from .models import Organization
+from guardian.decorators import permission_required
+
+from .constants import ORGTYPE_PRIVATE_BENEFACTOR,\
+    ORGANIZATION_EVENT_COMMENT, ORGANIZATION_EVENT_EMAIL_SENT
+from .forms import OrganizationEventForm, ContactPersonForm,\
+    NewContactForm, ContactActivationForm, ContactRoleForm
+from .models import Organization, OrganizationEvent, ContactPerson, Contact, ContactRole
 
 from funders.models import Funder
+from mails.utils import DirectMailUtil
+from mails.views import MailEditingSubView
+from organizations.decorators import has_contact
 from partners.models import ProspectivePartner, Partner
 
-from scipost.mixins import PermissionsMixin
+from scipost.mixins import PermissionsMixin, PaginationMixin
 
 
 class OrganizationCreateView(PermissionsMixin, CreateView):
@@ -48,8 +62,9 @@ class OrganizationDeleteView(PermissionsMixin, DeleteView):
     success_url = reverse_lazy('organizations:organizations')
 
 
-class OrganizationListView(ListView):
+class OrganizationListView(PaginationMixin, ListView):
     model = Organization
+    paginate_by = 50
 
     def get_context_data(self, *args, **kwargs):
         context = super().get_context_data(*args, **kwargs)
@@ -57,20 +72,27 @@ class OrganizationListView(ListView):
             context['nr_funders_wo_organization'] = Funder.objects.filter(organization=None).count()
             context['nr_prospartners_wo_organization'] = ProspectivePartner.objects.filter(
                 organization=None).count()
-            context['nr_partners_wo_organization'] = Partner.objects.filter(organization=None).count()
+            context['nr_partners_wo_organization'] = Partner.objects.filter(
+                organization=None).count()
         context['pubyears'] = range(int(timezone.now().strftime('%Y')), 2015, -1)
+        context['countrycodes'] = [code['country'] for code in list(
+            Organization.objects.all().distinct('country').values('country'))]
         return context
 
     def get_queryset(self):
         qs = super().get_queryset().exclude(orgtype=ORGTYPE_PRIVATE_BENEFACTOR)
+        country = self.request.GET.get('country')
         order_by = self.request.GET.get('order_by')
         ordering = self.request.GET.get('ordering')
+        if country:
+            qs = qs.filter(country=country)
         if order_by == 'country':
             qs = qs.order_by('country')
         elif order_by == 'name':
             qs = qs.order_by('name')
         elif order_by == 'nap':
-            qs = qs.order_by('cf_nr_associated_publications')
+            qs = qs.exclude(cf_nr_associated_publications__isnull=True
+            ).order_by('cf_nr_associated_publications')
         if ordering == 'desc':
             qs = qs.reverse()
         return qs
@@ -92,3 +114,281 @@ class OrganizationDetailView(DetailView):
         if not self.request.user.has_perm('scipost.can_manage_organizations'):
             queryset = queryset.exclude(orgtype=ORGTYPE_PRIVATE_BENEFACTOR)
         return queryset
+
+
+class OrganizationEventCreateView(PermissionsMixin, CreateView):
+    permission_required = 'scipost.can_manage_organizations'
+    model = OrganizationEvent
+    form_class = OrganizationEventForm
+    template_name = 'organizations/organizationevent_form.html'
+
+    def get_initial(self):
+        organization = get_object_or_404(Organization, pk=self.kwargs.get('pk'))
+        return {'organization': organization,
+                'noted_on': timezone.now,
+                'noted_by': self.request.user}
+
+    def get_success_url(self):
+        return reverse_lazy('organizations:organization_details',
+                            kwargs={'pk': self.object.organization.id})
+
+
+class OrganizationEventListView(PermissionsMixin, PaginationMixin, ListView):
+    permission_required = 'scipost.can_manage_organizations'
+    model = OrganizationEvent
+    paginate_by = 10
+
+
+class ContactPersonCreateView(PermissionsMixin, CreateView):
+    permission_required = 'scipost.can_add_contactperson'
+    model = ContactPerson
+    form_class= ContactPersonForm
+    template_name = 'organizations/contactperson_form.html'
+
+    def get_initial(self):
+        try:
+            organization = Organization.objects.get(pk=self.kwargs.get('organization_id'))
+            return {'organization': organization}
+        except Organization.DoesNotExist:
+            pass
+
+    def form_valid(self, form):
+        event = OrganizationEvent(
+            organization=form.cleaned_data['organization'],
+            event=ORGANIZATION_EVENT_COMMENT,
+            comments=('Added ContactPerson: %s %s' % (form.cleaned_data['first_name'],
+                                                      form.cleaned_data['last_name'])),
+            noted_on=timezone.now(),
+            noted_by=self.request.user)
+        event.save()
+        return super().form_valid(form)
+
+    def get_success_url(self):
+        return reverse_lazy('organizations:organization_details',
+                            kwargs={'pk': self.object.organization.id})
+
+
+class ContactPersonUpdateView(PermissionsMixin, UpdateView):
+    permission_required = 'scipost.can_add_contactperson'
+    model = ContactPerson
+    form_class= ContactPersonForm
+    template_name = 'organizations/contactperson_form.html'
+
+    def form_valid(self, form):
+        event = OrganizationEvent(
+            organization=form.cleaned_data['organization'],
+            event=ORGANIZATION_EVENT_COMMENT,
+            comments=('Updated ContactPerson: %s %s' % (form.cleaned_data['first_name'],
+                                                        form.cleaned_data['last_name'])),
+            noted_on=timezone.now(),
+            noted_by=self.request.user)
+        event.save()
+        return super().form_valid(form)
+
+    def get_success_url(self):
+        return reverse_lazy('organizations:organization_details',
+                            kwargs={'pk': self.object.organization.id})
+
+
+class ContactPersonDeleteView(UserPassesTestMixin, DeleteView):
+    model = ContactPerson
+
+    def test_func(self):
+        """
+        Allow ContactPerson delete to OrgAdmins and all Contacts for this Organization.
+        """
+        if self.request.user.has_perm('scipost.can_manage_organizations'):
+            return True
+        contactperson = get_object_or_404(ContactPerson, pk=self.kwargs.get('pk'))
+        return self.request.user.has_perm('can_view_org_contacts', contactperson.organization)
+
+    def get_success_url(self):
+        return reverse_lazy('organizations:organization_details',
+                            kwargs={'pk': self.object.organization.id})
+
+
+class ContactPersonListView(PermissionsMixin, ListView):
+    permission_required = 'scipost.can_add_contactperson'
+    model = ContactPerson
+
+
+@permission_required('scipost.can_manage_organizations', return_403=True)
+@transaction.atomic
+def email_contactperson(request, contactperson_id, mail=None):
+    contactperson = get_object_or_404(ContactPerson, pk=contactperson_id)
+
+    suffix = ''
+    if mail == 'followup':
+        code = 'org_contacts/contactperson_followup_mail'
+        suffix = ' (followup)'
+    else:
+        code = 'org_contacts/contactperson_initial_mail'
+        suffix = ' (initial)'
+    mail_request = MailEditingSubView(request, mail_code=code, contactperson=contactperson)
+    if mail_request.is_valid():
+        comments = 'Email{suffix} sent to ContactPerson {name}.'.format(
+            suffix=suffix, name=contactperson)
+        event = OrganizationEvent(
+            organization=contactperson.organization,
+            event=ORGANIZATION_EVENT_EMAIL_SENT,
+            comments=comments,
+            noted_on=timezone.now(),
+            noted_by=request.user)
+        event.save()
+        messages.success(request, 'Email successfully sent.')
+        mail_request.send()
+        return redirect(contactperson.organization.get_absolute_url())
+    else:
+        return mail_request.return_render()
+
+
+@permission_required('scipost.can_manage_SPB', return_403=True)
+def organization_add_contact(request, organization_id, contactperson_id=None):
+    organization = get_object_or_404(Organization, id=organization_id)
+    if contactperson_id:
+        contactperson = get_object_or_404(ContactPerson, id=contactperson_id)
+        initial = {
+            'title': contactperson.title,
+            'first_name': contactperson.first_name,
+            'last_name': contactperson.last_name,
+            'email': contactperson.email
+            }
+    else:
+        contactperson = None
+        initial = {}
+    form = NewContactForm(request.POST or None, initial=initial,
+                          organization=organization,
+                          contactperson=contactperson
+    )
+    if form.is_valid():
+        contact = form.save(current_user=request.user)
+        mail_sender = DirectMailUtil(
+            mail_code='org_contacts/email_contact_for_activation',
+            contact=contact)
+        mail_sender.send()
+        for role in contact.roles.all():
+            event = OrganizationEvent(
+                organization=role.organization,
+                event=ORGANIZATION_EVENT_COMMENT,
+                comments=('Contact for %s created; activation pending' % str(contact)),
+                noted_on=timezone.now(),
+                noted_by=request.user)
+            event.save()
+        messages.success(request, '<h3>Created contact: %s</h3>Email has been sent.'
+                         % str(contact))
+        return redirect(reverse('organizations:organization_details',
+                                kwargs={'pk': organization.id}))
+    context = {
+        'organization': organization,
+        'form': form
+    }
+    return render(request, 'organizations/organization_add_contact.html', context)
+
+
+def activate_account(request, activation_key):
+    contact = get_object_or_404(Contact, user__is_active=False,
+                                activation_key=activation_key,
+                                user__email__icontains=request.GET.get('email', None))
+
+    # TODO: Key Expires fallback
+    form = ContactActivationForm(request.POST or None, instance=contact.user)
+    if form.is_valid():
+        form.activate_user()
+        for role in contact.roles.all():
+            event = OrganizationEvent(
+                organization=role.organization,
+                event=ORGANIZATION_EVENT_COMMENT,
+                comments=('Contact %s activated their account' % str(contact)),
+                noted_on=timezone.now(),
+                noted_by=contact.user)
+            event.save()
+        messages.success(request, '<h3>Thank you for activating your account</h3>')
+        return redirect(reverse('organizations:dashboard'))
+    context = {
+        'contact': contact,
+        'form': form
+    }
+    return render(request, 'organizations/activate_account.html', context)
+
+
+@login_required
+def dashboard(request):
+    """
+    Administration page for Organization Contacts.
+
+    This page is meant as a personal page for Contacts, where they will for example be able
+    to read their personal data and agreements.
+    """
+    if not (request.user.has_perm('scipost.can_manage_organizations') or
+            has_contact(request.user)):
+        raise PermissionDenied
+    context = {
+        'contacts': Contact.objects.all()
+    }
+    if has_contact(request.user):
+        context['own_roles'] = request.user.org_contact.roles.all()
+    return render(request, 'organizations/dashboard.html', context)
+
+
+class ContactRoleUpdateView(UserPassesTestMixin,  UpdateView):
+    """
+    Update a ContactRole.
+    """
+    model = ContactRole
+    form_class = ContactRoleForm
+    template_name = 'organizations/contactrole_form.html'
+
+    def test_func(self):
+        """
+        Allow ContactRole update to OrgAdmins and all Contacts for this Organization.
+        """
+        if self.request.user.has_perm('scipost.can_manage_organizations'):
+            return True
+        contactrole = get_object_or_404(ContactRole, pk=self.kwargs.get('pk'))
+        return self.request.user.has_perm('can_view_org_contacts', contactrole.organization)
+
+    def get_success_url(self):
+        return reverse_lazy('organizations:organization_details',
+                            kwargs={'pk': self.object.organization.id})
+
+
+class ContactRoleDeleteView(PermissionsMixin, DeleteView):
+    """
+    Delete a ContactRole.
+    """
+    permission_required = 'scipost.can_manage_organizations'
+    model = ContactRole
+
+    def get_success_url(self):
+        return reverse_lazy('organizations:organization_details',
+                            kwargs={'pk': self.object.organization.id})
+
+
+@permission_required('scipost.can_manage_organizations', return_403=True)
+@transaction.atomic
+def email_contactrole(request, contactrole_id, mail=None):
+    contactrole = get_object_or_404(ContactRole, pk=contactrole_id)
+
+    suffix = ''
+    if mail == 'renewal':
+        code = 'org_contacts/contactrole_subsidy_renewal_mail'
+        suffix = ' (subsidy renewal query)'
+    else:
+        code = 'org_contacts/contactrole_generic_mail'
+        suffix = ' (generic)'
+    mail_request = MailEditingSubView(request, mail_code=code, contactrole=contactrole)
+    if mail_request.is_valid():
+        comments = 'Email{suffix} sent to Contact {name}.'.format(
+            suffix=suffix, name=contactrole.contact)
+        event = OrganizationEvent(
+            organization=contactrole.organization,
+            event=ORGANIZATION_EVENT_EMAIL_SENT,
+            comments=comments,
+            noted_on=timezone.now(),
+            noted_by=request.user)
+        event.save()
+        messages.success(request, 'Email successfully sent.')
+        mail_request.send()
+        return redirect(contactrole.organization.get_absolute_url())
+    else:
+        return mail_request.return_render()
diff --git a/package.json b/package.json
index d1b19598bf1e9ce5f936f6408157a529a47d3e6b..49222490e65b7db14dc428bea83c8aa211799450 100644
--- a/package.json
+++ b/package.json
@@ -18,35 +18,36 @@
   "author": "SciPost",
   "homepage": "https://www.scipost.org",
   "devDependencies": {
-    "ajv": "^5.2.2",
+    "ajv": "^5.5.2",
     "bootstrap": "^4.1.3",
-    "clean-webpack-plugin": "^0.1.15",
-    "css-loader": "^0.28.4",
+    "clean-webpack-plugin": "^0.1.19",
+    "css-loader": "^0.28.11",
     "enhanced-resolve": "^3.4.1",
     "exports-loader": "^0.6.4",
-    "extract-text-webpack-plugin": "^3.0.0",
+    "extract-text-webpack-plugin": "^3.0.2",
     "file-loader": "^0.11.2",
     "imports-loader": "^0.7.1",
     "jquery": "^3.3.1",
     "jquery-ui": "^1.12.1",
     "node-loader": "^0.6.0",
-    "node-sass": "^4.4.0",
+    "node-sass": "^4.11.0",
     "popper.js": "^1.14.3",
     "postcss-load-config": "^1.2.0",
-    "postcss-loader": "^2.0.6",
+    "postcss-loader": "^2.1.6",
     "resolve-url-loader": "^1.6.1",
-    "sass-loader": "^6.0.6",
-    "sass-resources-loader": "^1.3.0",
-    "style-loader": "^0.13.1",
-    "tapable": "^0.2.8",
-    "tether": "^1.4.0",
+    "sass-loader": "^6.0.7",
+    "sass-resources-loader": "^1.3.5",
+    "style-loader": "^0.13.2",
+    "tapable": "^0.2.9",
+    "tether": "^1.4.5",
     "url-loader": "^1.1.1",
-    "webpack": "^3.5.4",
+    "webpack": "^3.12.0",
     "webpack-bundle-tracker": "^0.3.0",
     "webpack-glob-entry": "^2.1.1"
   },
   "dependencies": {
     "bootstrap-loader": "^2.2.0",
+    "nan": "git+https://github.com/nodejs/nan.git",
     "npm": "^6.4.1",
     "npm-install-peers": "^1.2.1",
     "schema-utils": "^0.3.0"
diff --git a/partners/forms.py b/partners/forms.py
index aa34fb488046390a5b1bb9ee4a2c8d2d5fa7c4a1..531850532c938faf8b753d95af7f4aa136c6f3a3 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 9bc5ea8245e16761f66dc012424502a166be5873..9ddb4324fa407da056e4c03c636f65cab5283561 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,
diff --git a/requirements.txt b/requirements.txt
index 124e5a6e560b27f980127a1bcb9d60da312079a8..1cb0595fbc83ac7f0fb4fbe8f5aa25faa3b1ab6d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,7 +11,7 @@ requests==2.18.3
 
 # Django packages
 django_ajax_selects==1.6
-django-countries==4.6.1
+django-countries==5.3.3
 django-debug-toolbar==1.8
 django-extensions==1.7.6
 django-filter==1.0.4
diff --git a/scipost/admin.py b/scipost/admin.py
index 68435d47199dfc51210a290305d02703b8902eb7..44c216847c538662a78e3caba5c4f4e84bb6df3f 100644
--- a/scipost/admin.py
+++ b/scipost/admin.py
@@ -12,6 +12,7 @@ from scipost.models import Contributor, Remark,\
                            AuthorshipClaim, PrecookedEmail,\
                            EditorialCollege, EditorialCollegeFellowship, UnavailabilityPeriod
 
+from organizations.admin import ContactInline
 from partners.admin import ContactToUserInline
 from production.admin import ProductionUserInline
 from submissions.models import Submission
@@ -38,7 +39,8 @@ class ContributorInline(admin.StackedInline):
 class UserAdmin(UserAdmin):
     inlines = [
         ContributorInline,
-        ContactToUserInline,
+        ContactInline,
+        ContactToUserInline, # TODO:PartnersDeprec remove
         ProductionUserInline
         ]
     list_display = ['username', 'email', 'first_name', 'last_name',
diff --git a/scipost/forms.py b/scipost/forms.py
index eb2fd287df916517c3c61a8f9edca52a0b378bfd..5e6c95dba26f5e1dbcaac223cc53530fbbc465ca 100644
--- a/scipost/forms.py
+++ b/scipost/forms.py
@@ -34,7 +34,7 @@ from .models import Contributor, DraftInvitation, UnavailabilityPeriod, \
 
 from affiliations.models import Affiliation, Institution
 from common.forms import MonthYearWidget, ModelChoiceFieldwithid
-from partners.decorators import has_contact
+from organizations.decorators import has_contact
 
 from colleges.models import Fellowship, PotentialFellowshipEvent
 from commentaries.models import Commentary
@@ -343,7 +343,7 @@ class AuthenticationForm(forms.Form):
             if has_contributor(request.user):
                 return reverse_lazy('scipost:personal_page')
             elif has_contact(request.user):
-                return reverse_lazy('partners:dashboard')
+                return reverse_lazy('organizations:dashboard')
             else:
                 return reverse_lazy('scipost:index')
         return redirect_to
diff --git a/scipost/management/commands/add_groups_and_permissions.py b/scipost/management/commands/add_groups_and_permissions.py
index 901687f2afd869c2f3fb4d36dab65d80b0c598fe..4c1c62853e268ece86b6a1c2b91b708853634bf5 100644
--- a/scipost/management/commands/add_groups_and_permissions.py
+++ b/scipost/management/commands/add_groups_and_permissions.py
@@ -34,6 +34,8 @@ class Command(BaseCommand):
         ProductionSupervisors, created = Group.objects.get_or_create(name='Production Supervisor')
         ProductionOfficers, created = Group.objects.get_or_create(name='Production Officers')
 
+        OrgContacts, created = Group.objects.get_or_create(name='Organization Contacts')
+
         PartnersAdmin, created = Group.objects.get_or_create(name='Partners Administrators')
         PartnersOfficers, created = Group.objects.get_or_create(name='Partners Officers')
         PartnerAccounts, created = Group.objects.get_or_create(name='Partners Accounts')
@@ -41,11 +43,21 @@ class Command(BaseCommand):
         # Create Permissions
         content_type = ContentType.objects.get_for_model(Contributor)
 
-        # Supporting Partners
+        # Organizations
         can_manage_organizations, created = Permission.objects.get_or_create(
             codename='can_manage_organizations',
             name='Can manage Organizations',
             content_type=content_type)
+        can_add_contactperson, created = Permission.objects.get_or_create(
+            codename='can_add_contactperson',
+            name='Can add ContactPerson',
+            content_type=content_type)
+        can_view_contactrole_list, created = Permission.objects.get_or_create(
+            codename='can_view_contactrole_list',
+            name='Can view ContactRole list',
+            content_type=content_type)
+
+        # Supporting Partners
         can_manage_SPB, created = Permission.objects.get_or_create(
             codename='can_manage_SPB',
             name='Can manage Supporting Partners Board',
@@ -474,6 +486,11 @@ class Command(BaseCommand):
             can_upload_proofs,
         ])
 
+        OrgContacts.permissions.set([
+            can_add_contactperson,
+            can_view_contactrole_list,
+            ])
+
         PartnersAdmin.permissions.set([
             can_manage_organizations,
             can_read_partner_page,
diff --git a/scipost/templates/scipost/navbar.html b/scipost/templates/scipost/navbar.html
index e364be488e929e15aca304d3354d5042b76cfa76..f6d41fb08c1b749be175cbcfdab0bbb2829898cf 100644
--- a/scipost/templates/scipost/navbar.html
+++ b/scipost/templates/scipost/navbar.html
@@ -63,9 +63,9 @@
                         <a class="nav-link" href="{% url 'scipost:personal_page' %}">Personal Page</a>
                       </li>
                   {% endif %}
-                  {% if user.partner_contact %}
-                      <li class="nav-item{% if '/partners/dashboard' in request.path %} active{% endif %}">
-                        <a class="nav-link" href="{% url 'partners:dashboard' %}">Partner Page</a>
+                  {% if perms.scipost.can_manage_organizations or user.org_contact %}
+                      <li class="nav-item{% if '/organizations/dashboard' in request.path %} active{% endif %}">
+                        <a class="nav-link" href="{% url 'organizations:dashboard' %}">Orgs dashboard</a>
                       </li>
                   {% endif %}
               {% else %}
diff --git a/scipost/templates/scipost/update_personal_data.html b/scipost/templates/scipost/update_personal_data.html
index bf638ee1511c87ace3d42a6608f795ce215c41dc..2d28ecfec6cd61b64dd70601d48c89e77b59b6f0 100644
--- a/scipost/templates/scipost/update_personal_data.html
+++ b/scipost/templates/scipost/update_personal_data.html
@@ -50,6 +50,9 @@
     <div class="row justify-content-center">
         <div class="col-lg-6">
             <h1 class="mb-3">Update your personal data</h1>
+	    {% if contact_form %}
+	    {{ contact_form|bootstrap }}
+	    {% endif %}
             {{ user_form|bootstrap }}
             {% if cont_form %}
             	{{ cont_form|bootstrap }}
diff --git a/scipost/views.py b/scipost/views.py
index efdec24ed6a58c2b28dbec591c325d3a752c4082..b235350cf2533408e537a93f975a414ca33c00b0 100644
--- a/scipost/views.py
+++ b/scipost/views.py
@@ -53,7 +53,9 @@ from invitations.constants import STATUS_REGISTERED
 from invitations.models import RegistrationInvitation
 from journals.models import Publication, Journal, PublicationAuthorsTable
 from news.models import NewsItem
-from organizations.models import Organization
+from organizations.decorators import has_contact
+from organizations.models import Organization, Contact
+from organizations.forms import UpdateContactDataForm
 from partners.models import MembershipAgreement
 from submissions.models import Submission, RefereeInvitation, Report, EICRecommendation
 from theses.models import ThesisLink
@@ -401,7 +403,8 @@ def login_view(request):
                                       '(our admins will verify your credentials very soon)'))
         elif form.user_is_inactive():
             form.add_error(None, ('Your account is not yet activated. '
-                                  'Please first activate your account.'))
+                                  'Please first activate your account by clicking on the '
+                                  'activation link we emailed you.'))
         else:
             form.add_error(None, 'Invalid username/password.')
     context = {'form': form}
@@ -679,6 +682,8 @@ def personal_page(request, tab='account'):
         contributor = Contributor.objects.select_related('user').get(user=request.user)
         context['needs_validation'] = contributor.status != NORMAL_CONTRIBUTOR
     except Contributor.DoesNotExist:
+        if has_contact(request.user):
+            return redirect(reverse('organizations:dashboard'))
         contributor = None
 
     if contributor:
@@ -736,6 +741,23 @@ def _update_personal_data_user_only(request):
     return render(request, 'scipost/update_personal_data.html', context)
 
 
+def _update_personal_data_contact(request):
+    contact = Contact.objects.get(user=request.user)
+    user_form = UpdateUserDataForm(request.POST or None, instance=request.user)
+    contact_form = UpdateContactDataForm(request.POST or None, instance=contact)
+    if user_form.is_valid() and contact_form.is_valid():
+        user_form.save()
+        contact_form.save()
+        messages.success(request, 'Your personal data has been updated.')
+        return redirect(reverse('organizations:dashboard'))
+
+    context = {
+        'user_form': user_form,
+        'contact_form': contact_form,
+    }
+    return render(request, 'scipost/update_personal_data.html', context)
+
+
 def _update_personal_data_contributor(request):
     contributor = Contributor.objects.get(user=request.user)
     user_form = UpdateUserDataForm(request.POST or None, instance=request.user)
@@ -763,6 +785,8 @@ def _update_personal_data_contributor(request):
 def update_personal_data(request):
     if has_contributor(request.user):
         return _update_personal_data_contributor(request)
+    elif has_contact(request.user):
+        return _update_personal_data_contact(request)
     return _update_personal_data_user_only(request)
 
 
diff --git a/submissions/templates/submissions/pool/pool.html b/submissions/templates/submissions/pool/pool.html
index 7ffb70f9df626f6a9da6bc9a44ae8e587c8c90a9..8e7a1ba6686dcdb4e773c7205db08f20f6a6fd13 100644
--- a/submissions/templates/submissions/pool/pool.html
+++ b/submissions/templates/submissions/pool/pool.html
@@ -27,7 +27,7 @@
   </div>
   <div class="col-6">
     <p class="p-2" style="border: 1px solid red;">
-      Do you know know qualified candidates who could serve as Fellow in a College?<br/>
+      Do you know qualified candidates who could serve as Fellow in a College?<br/>
       Nominate them by <a href="{% url 'colleges:potential_fellowship_create' %}">adding a Potential Fellowship</a>.
       {% if nr_potfels_to_vote_on > 0 %}
       <br/>
diff --git a/templates/email/org_contacts/contactperson_followup_mail.html b/templates/email/org_contacts/contactperson_followup_mail.html
new file mode 100644
index 0000000000000000000000000000000000000000..0eaa8ec76b9c91fd51ccb0b1e56f625e06d51cc7
--- /dev/null
+++ b/templates/email/org_contacts/contactperson_followup_mail.html
@@ -0,0 +1,39 @@
+<p>
+  Dear {% if contactperson %}{{ contactperson.get_title_display }} {{ contactperson.last_name }}{% else %}colleagues{% endif %},
+</p>
+<p>
+  We recently contacted you concerning SciPost, to probe your organization's interest in becoming a Sponsor. With this follow-up email, I would simply like to check whether you got the original message.
+</p>
+<p>
+  <a href="https://scipost.org">SciPost</a> is a next-generation publication portal aiming to transform the business of scientific publishing. You can find a one-page summary in <a href="https://scipost.org/static/sponsors/SciPost_Sponsors_Board_Prospectus.pdf">our online prospectus</a> outlining the reasons why joining would be beneficial for your institution.
+</p>
+<p>
+  You can also find a summary of how your organization has benefitted from our activities at <a href="https://scipost.org{{ contactperson.organization.get_absolute_url }}">this link</a>.
+</p>
+<p>
+  I will be happy to provide any required further details. If you are interested, you can simply get in touch via this address (sponsors@scipost.org). I sincerely hope that SciPost will be able to count on your support.
+</p>
+<p>
+  If you not the right representative to get in touch with, could you please forward this to the right person, or let us know?
+</p>
+<p>
+    Many thanks in advance,
+</p>
+<p>
+    On behalf of the SciPost Foundation,<br><br>
+    Prof. dr Jean-Sébastien Caux<br>
+    J.S.Caux@uva.nl&nbsp;jscaux@scipost.org<br>
+    https://jscaux.org<br>
+    ---------------------------------------------<br>
+    Institute for Theoretical Physics<br>
+    University of Amsterdam<br>
+    Science Park 904<br>
+    1098 XH  Amsterdam<br>
+    The Netherlands<br>
+    ---------------------------------------------<br>
+    tel.: +31 (0)20 5255775<br>
+    fax: +31 (0)20 5255778<br>
+    ---------------------------------------------
+</p>
+
+{% include 'email/_footer.html' %}
diff --git a/templates/email/org_contacts/contactperson_followup_mail.json b/templates/email/org_contacts/contactperson_followup_mail.json
new file mode 100644
index 0000000000000000000000000000000000000000..2dfd72a649833a596ad48a53e21442521a6ccbfd
--- /dev/null
+++ b/templates/email/org_contacts/contactperson_followup_mail.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: Sponsors",
+    "to_address": "email",
+    "bcc_to": "sponsors@scipost.org",
+    "from_address_name": "SciPost Sponsors",
+    "from_address": "sponsors@scipost.org",
+    "context_object": "contactperson"
+}
diff --git a/templates/email/org_contacts/contactperson_initial_mail.html b/templates/email/org_contacts/contactperson_initial_mail.html
new file mode 100644
index 0000000000000000000000000000000000000000..df1322cb97525cec76b75466a2f90ded34a39b61
--- /dev/null
+++ b/templates/email/org_contacts/contactperson_initial_mail.html
@@ -0,0 +1,41 @@
+<p>
+  Dear {% if contactperson %}{{ contactperson.get_title_display }} {{ contactperson.last_name }}{% else %}colleagues{% endif %},
+</p>
+<p>
+  You might by now have heard of SciPost, a not-for-profit initiative aiming to bring disruptive change to academic publishing practices.
+</p>
+<p>
+  The site is anchored at <a href="https://scipost.org">SciPost.org</a>. Many further details about SciPost, its principles, ideals and implementation can be found at the <a href="https://scipost.org/about">about page</a> and <a href="https://scipost.org/FAQ">our FAQ</a>.
+</p>
+<p>
+  You can also find a summary of how your organization has benefitted from our activities at <a href="https://scipost.org{{ contactperson.organization.get_absolute_url }}">this link</a>.
+</p>
+<p>
+  As explained on our <a href="https://scipost.org/sponsors">Sponsors page</a>, SciPost follows a completely different funding model than traditional publishers, and provides a cost-slashing alternative to existing platforms. SciPost charges neither subscription fees, nor article processing charges; its activities are instead to be collectively financed by a worldwide consortium of Sponsors, formed by institutions and organizations which directly or indirectly benefit from SciPost’s activities.
+</p>
+<p>
+  A short summary and reasons for your organization to become Sponsors are given in <a href="https://scipost.org/static/sponsors/SciPost_Sponsors_Board_Prospectus.pdf">our one-page prospectus</a>.
+</p>
+<p>
+  In <a href="https://scipost.org/static/sponsors/SciPost_Sponsorship_Agreement.pdf">the agreement template</a>, you will find many more specific details about our operations, requirements and funding strategy.
+</p>
+<p>
+  It would be a privilege to welcome your organization as a Sponsor. I am hereby contacting you to enquire whether your institution would consider joining? If you are interested, you can simply get in touch via this address (sponsors@scipost.org). I sincerely hope that SciPost will be able to count on your support.
+</p>
+
+<p>
+    On behalf of the SciPost Foundation,<br><br>
+    Prof. dr Jean-Sébastien Caux<br>
+    J.S.Caux@uva.nl<br>
+    http://jscaux.org<br>
+    ---------------------------------------------<br>
+    Institute for Theoretical Physics<br>
+    University of Amsterdam<br>
+    Science Park 904<br>
+    1098 XH  Amsterdam<br>
+    The Netherlands<br>
+    ---------------------------------------------<br>
+    tel.: +31 (0)20 5255775<br>
+    fax: +31 (0)20 5255778<br>
+    ---------------------------------------------
+</p>
diff --git a/templates/email/org_contacts/contactperson_initial_mail.json b/templates/email/org_contacts/contactperson_initial_mail.json
new file mode 100644
index 0000000000000000000000000000000000000000..2dfd72a649833a596ad48a53e21442521a6ccbfd
--- /dev/null
+++ b/templates/email/org_contacts/contactperson_initial_mail.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: Sponsors",
+    "to_address": "email",
+    "bcc_to": "sponsors@scipost.org",
+    "from_address_name": "SciPost Sponsors",
+    "from_address": "sponsors@scipost.org",
+    "context_object": "contactperson"
+}
diff --git a/templates/email/org_contacts/contactrole_generic_mail.html b/templates/email/org_contacts/contactrole_generic_mail.html
new file mode 100644
index 0000000000000000000000000000000000000000..c226178ad8726da945b840e01d12a040a68f495d
--- /dev/null
+++ b/templates/email/org_contacts/contactrole_generic_mail.html
@@ -0,0 +1,6 @@
+<p>
+  Dear {{ contactrole.contact.get_title_display }} {{ contactrole.contact.user.last_name }},
+</p>
+<p>
+  On behalf of the SciPost Foundation,<br><br>
+</p>
diff --git a/templates/email/org_contacts/contactrole_generic_mail.json b/templates/email/org_contacts/contactrole_generic_mail.json
new file mode 100644
index 0000000000000000000000000000000000000000..c5b4b1ec67222ef39d899af1621e1b90c514eb20
--- /dev/null
+++ b/templates/email/org_contacts/contactrole_generic_mail.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: Sponsors",
+    "to_address": "contact.user.email",
+    "bcc_to": "sponsors@scipost.org",
+    "from_address_name": "SciPost Sponsors",
+    "from_address": "sponsors@scipost.org",
+    "context_object": "contactrole"
+}
diff --git a/templates/email/org_contacts/contactrole_subsidy_renewal_mail.html b/templates/email/org_contacts/contactrole_subsidy_renewal_mail.html
new file mode 100644
index 0000000000000000000000000000000000000000..6dbbf6bf80d30b25b0e48a71db73ab97f82b8f41
--- /dev/null
+++ b/templates/email/org_contacts/contactrole_subsidy_renewal_mail.html
@@ -0,0 +1,12 @@
+<p>
+  Dear {{ contactrole.contact.get_title_display }} {{ contactrole.contact.user.last_name }},
+</p>
+<p>
+  Your organization ({{ contactrole.organization }}) has been sponsoring SciPost (see details at <a href="https://scipost.org{{ contactrole.organization.get_absolute_url }}">this link</a>), for which we are extremely grateful.
+</p>
+<p>
+  Your latest sponsorship period ends on {{ contactrole.organization.latest_subsidy_date_until }}. We would be extremely grateful for your continued support, and would hereby like to enquire whether we can start the renewal procedure.
+</p>
+<p>
+  On behalf of the SciPost Foundation,<br><br>
+</p>
diff --git a/templates/email/org_contacts/contactrole_subsidy_renewal_mail.json b/templates/email/org_contacts/contactrole_subsidy_renewal_mail.json
new file mode 100644
index 0000000000000000000000000000000000000000..544f6dbc421e82e3aef920c04588f821f4d957f3
--- /dev/null
+++ b/templates/email/org_contacts/contactrole_subsidy_renewal_mail.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: Sponsorship renewal",
+    "to_address": "contact.user.email",
+    "bcc_to": "sponsors@scipost.org",
+    "from_address_name": "SciPost Sponsors",
+    "from_address": "sponsors@scipost.org",
+    "context_object": "contactrole"
+}
diff --git a/templates/email/org_contacts/email_contact_for_activation.html b/templates/email/org_contacts/email_contact_for_activation.html
new file mode 100644
index 0000000000000000000000000000000000000000..2419eb7796a0377980731a164e0e3579fae09feb
--- /dev/null
+++ b/templates/email/org_contacts/email_contact_for_activation.html
@@ -0,0 +1,20 @@
+<p>Dear {{contact.get_title_display}} {{contact.user.first_name}} {{contact.user.last_name}},</p>
+
+<p>
+    Many thanks for sponsoring SciPost. We have now created a personal account for you on scipost.org, which will allow you to access all relevant information and functionalities related to sponsoring.
+</p>
+<p>
+    In order to activate your account, please navigate to <a href="https://scipost.org{% url 'organizations:activate_account' contact.activation_key %}?email={{contact.user.email}}">this link</a>. You will be asked to choose a password, after which you will be able to login.
+</p>
+<p>
+    After logging in, you will find a “Org dashboard” link in the top menu, which will take you to your info page.
+</p>
+<p>
+    We are very pleased to welcome you to SciPost, and will be happy to answer any questions you might have.
+</p>
+<p>
+    Sincerely,<br><br>
+    SciPost and its Sponsors Board
+</p>
+
+{% include 'email/_footer.html' %}
diff --git a/templates/email/org_contacts/email_contact_for_activation.json b/templates/email/org_contacts/email_contact_for_activation.json
new file mode 100644
index 0000000000000000000000000000000000000000..93aaedd2bd6b1f37ade694374b5643406860ba30
--- /dev/null
+++ b/templates/email/org_contacts/email_contact_for_activation.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: account activation",
+    "to_address": "user.email",
+    "bcc_to": "sponsors@scipost.org",
+    "from_address_name": "SciPost Sponsors Admin",
+    "from_address": "sponsors@scipost.org",
+    "context_object": "contact"
+}