diff --git a/SciPost_v1/settings/staging.py b/SciPost_v1/settings/staging.py
index 48120c079d0f89189a545a27d9afafd9d4053968..62c0b2932720cb11fc62559d50d1bb798f20b1af 100644
--- a/SciPost_v1/settings/staging.py
+++ b/SciPost_v1/settings/staging.py
@@ -26,3 +26,6 @@ LOGGING['handlers']['scipost_file_doi']['filename'] = '/home/scipoststg/webapps/
 SESSION_COOKIE_SECURE = True
 CSRF_COOKIE_SECURE = True
 
+# Email
+EMAIL_BACKEND = 'mails.backends.filebased.ModelEmailBackend'
+EMAIL_BACKEND_ORIGINAL = 'django.core.mail.backends.dummy.EmailBackend'  # Disable real processing
diff --git a/affiliations/managers.py b/affiliations/managers.py
index e6a0872050e865cd4a2e7fdf3efcab9fae156f2e..11d16f9ecedba5af4c15825c04fd3a594c28193b 100644
--- a/affiliations/managers.py
+++ b/affiliations/managers.py
@@ -16,3 +16,7 @@ class AffiliationQuerySet(models.QuerySet):
             Q(begin_date__isnull=True, end_date__gte=today) |
             Q(begin_date__lte=today, end_date__gte=today) |
             Q(begin_date__isnull=True, end_date__isnull=True))
+
+class InstitutionQuerySet(models.QuerySet):
+    def has_publications(self):
+        return self.filter(publications__isnull=False)
diff --git a/affiliations/models.py b/affiliations/models.py
index 40f41195d423482d132f86ceb33536c7fb26e7ea..faf52284684048e97d7729cce9e03c55e87862d8 100644
--- a/affiliations/models.py
+++ b/affiliations/models.py
@@ -10,18 +10,19 @@ from django_countries.fields import CountryField
 from scipost.models import Contributor
 
 from .constants import INSTITUTION_TYPES, TYPE_UNIVERSITY
-from .managers import AffiliationQuerySet
+from .managers import AffiliationQuerySet, InstitutionQuerySet
 
 
 class Institution(models.Model):
-    """
-    Any (scientific) Institution in the world should ideally have a SciPost registration.
-    """
+    """Any (scientific) Institution with a SciPost registration."""
+
     name = models.CharField(max_length=255)
     acronym = models.CharField(max_length=16, blank=True)
     country = CountryField()
     type = models.CharField(max_length=16, choices=INSTITUTION_TYPES, default=TYPE_UNIVERSITY)
 
+    objects = InstitutionQuerySet.as_manager()
+
     class Meta:
         default_related_name = 'institutions'
         ordering = ['country']
@@ -30,9 +31,11 @@ class Institution(models.Model):
         return '{name} ({country})'.format(name=self.name, country=self.get_country_display())
 
     def get_absolute_url(self):
+        """Return the Institution detail page."""
         return reverse('affiliations:institution_details', args=(self.id,))
 
     def contributors(self):
+        """All Contributor instances related to the Institution."""
         return Contributor.objects.filter(affiliations__institution=self)
 
 
diff --git a/affiliations/templates/affiliations/base.html b/affiliations/templates/affiliations/base.html
new file mode 100644
index 0000000000000000000000000000000000000000..6e6300f5ffebd97a0a4a9cc57c02baa65e50dccf
--- /dev/null
+++ b/affiliations/templates/affiliations/base.html
@@ -0,0 +1,13 @@
+{% extends 'scipost/base.html' %}
+
+{% block breadcrumb %}
+    <div class="container-outside header">
+        <div class="container">
+            <nav class="breadcrumb hidden-sm-down">
+                {% block breadcrumb_items %}
+                    <a href="{% url 'affiliations:institutions' %}" class="breadcrumb-item">Institutions</a>
+                {% endblock %}
+            </nav>
+        </div>
+    </div>
+{% endblock %}
diff --git a/affiliations/templates/affiliations/institution_detail.html b/affiliations/templates/affiliations/institution_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..641f629292c7e8d000698fcb847373ea3e9af177
--- /dev/null
+++ b/affiliations/templates/affiliations/institution_detail.html
@@ -0,0 +1,26 @@
+{% extends 'affiliations/base.html' %}
+
+{% load bootstrap %}
+
+{% block pagetitle %}: Institution details{% endblock pagetitle %}
+
+{% block breadcrumb_items %}
+    {{ block.super }}
+    <span class="breadcrumb-item">{{ institution }}</span>
+{% endblock %}
+
+{% block content %}
+
+<h1 class="highlight">Institution {{ institution }}</h1>
+
+<ul>
+    {% for publication in institution.publications.all %}
+        <li>
+            <a href="{{ publication.get_absolute_url }}">{{ publication.title }}</a>
+            <br>by {{ publication.author_list }},
+            <br>{{ publication.citation }}
+        </li>
+    {% endfor %}
+</ul>
+
+{% endblock content %}
diff --git a/affiliations/templates/affiliations/institution_list.html b/affiliations/templates/affiliations/institution_list.html
index 50d0b8ea36fd872feb75a211c4cf652822c9bd47..a76c137dd6e2ba85102ca14a1f173535d6fab87e 100644
--- a/affiliations/templates/affiliations/institution_list.html
+++ b/affiliations/templates/affiliations/institution_list.html
@@ -1,23 +1,29 @@
-{% extends 'scipost/_personal_page_base.html' %}
+{% extends 'affiliations/base.html' %}
 
 
 {% block pagetitle %}: Institutions{% endblock pagetitle %}
 
+
 {% block breadcrumb_items %}
-    {{ block.super }}
     <span class="breadcrumb-item">Institutions</span>
 {% endblock %}
 
 {% block content %}
 
-<h1>All Institutions in the database</h1>
+<h1 class="highlight">Institutions</h1>
+
+<h3>All Institutions with a SciPost publication</h3>
 
 {% if is_paginated %}
     {% include 'partials/pagination.html' with page_obj=page_obj %}
 {% endif %}
+
 <ul>
     {% for institution in object_list %}
-        <li><a href="{% url 'affiliations:institution_details' institution.id %}">{{ institution }}</a></li>
+        <li>
+            <a href="{{ institution.get_absolute_url }}">{{ institution }}</a>
+            {% if perms.scipost.can_manage_affiliations %} &middot; <a href="{% url 'affiliations:institution_edit' institution.id %}"><i class="fa fa-pencil"></i></a>{% endif %}
+        </li>
     {% empty %}
         <li><em>There are no Institutions known yet.</em><li>
     {% endfor %}
diff --git a/affiliations/urls.py b/affiliations/urls.py
index 0b839a4656c5434cacde2f183db38203ed1182fc..22b6fc62eb3081d47741c2169c86467015116523 100644
--- a/affiliations/urls.py
+++ b/affiliations/urls.py
@@ -8,8 +8,10 @@ from . import views
 
 urlpatterns = [
     url(r'^$', views.InstitutionListView.as_view(), name='institutions'),
-    url(r'^(?P<institution_id>[0-9]+)/$', views.InstitutionUpdateView.as_view(),
+    url(r'^(?P<institution_id>[0-9]+)/$', views.InstitutionDetailView.as_view(),
         name='institution_details'),
+    url(r'^(?P<institution_id>[0-9]+)/edit', views.InstitutionUpdateView.as_view(),
+        name='institution_edit'),
     url(r'^(?P<institution_id>[0-9]+)/merge$', views.merge_institutions,
         name='merge_institutions'),
 ]
diff --git a/affiliations/views.py b/affiliations/views.py
index 83e94a2c94c16ab8d865b246803bdc04c6d9ab47..9de5a4d024652bae71457646716549a6560fe995 100644
--- a/affiliations/views.py
+++ b/affiliations/views.py
@@ -7,6 +7,7 @@ from django.contrib import messages
 from django.contrib.auth.decorators import permission_required
 from django.urls import reverse
 from django.utils.decorators import method_decorator
+from django.views.generic.detail import DetailView
 from django.views.generic.edit import UpdateView
 from django.views.generic.list import ListView
 from django.shortcuts import get_object_or_404
@@ -15,10 +16,14 @@ from .forms import InstitutionMergeForm
 from .models import Institution
 
 
-@method_decorator(permission_required('scipost.can_manage_affiliations'), name='dispatch')
 class InstitutionListView(ListView):
+    queryset = Institution.objects.has_publications()
+    paginate_by = 20
+
+
+class InstitutionDetailView(DetailView):
     model = Institution
-    paginate_by = 100
+    pk_url_kwarg = 'institution_id'
 
 
 @method_decorator(permission_required('scipost.can_manage_affiliations'), name='dispatch')
@@ -53,4 +58,4 @@ def merge_institutions(request, institution_id):
         messages.success(request, 'Institution {a} merged into {b}'.format(
             a=form.cleaned_data.get('institution', '?'), b=institution))
 
-    return redirect(reverse('affiliations:institution_details', args=(institution.id,)))
+    return redirect(reverse('affiliations:institution_edit', args=(institution.id,)))
diff --git a/colleges/models.py b/colleges/models.py
index 8f4f8ac110f51050320e5a738ea5d8c652f4f3bd..312021771eb5501790b86f011e264e206628d2c9 100644
--- a/colleges/models.py
+++ b/colleges/models.py
@@ -13,13 +13,15 @@ from .managers import FellowQuerySet
 
 
 class Fellowship(TimeStampedModel):
-    """
-    Editorial College Fellowship connecting Editorial College and Contributors,
-    possibly with a limiting start/until date.
+    """A Fellowship gives access to the Submission Pool to Contributors.
+
+    Editorial College Fellowship connects the Editorial College and Contributors,
+    possibly with a limiting start/until date and/or a Proceedings event.
 
     The date range will effectively be used while determining 'the pool' for a specific
     Submission, so it has a direct effect on the submission date.
     """
+
     contributor = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE,
                                     related_name='fellowships')
     start_date = models.DateField(null=True, blank=True)
@@ -39,15 +41,15 @@ class Fellowship(TimeStampedModel):
         return _str
 
     def get_absolute_url(self):
+        """Return the admin fellowship page."""
         return reverse('colleges:fellowship', args=(self.id,))
 
     def sibling_fellowships(self):
-        """
-        Return all Fellowships that are directly related to the Fellow of this Fellowship.
-        """
+        """Return all Fellowships that are directly related to the Fellow of this Fellowship."""
         return self.contributor.fellowships.all()
 
     def is_active(self):
+        """Check if the instance is within start and until date."""
         today = datetime.date.today()
         if not self.start_date:
             if not self.until_date:
diff --git a/colleges/views.py b/colleges/views.py
index 14e4765853905caf5136d68b349e40d26eaf769b..babe8a45304bc2f92231d82ffa63a6c7a3f2ecec 100644
--- a/colleges/views.py
+++ b/colleges/views.py
@@ -19,9 +19,7 @@ from .models import Fellowship
 @login_required
 @permission_required('scipost.can_manage_college_composition', raise_exception=True)
 def fellowships(request):
-    """
-    List all fellowships to be able to edit them, or create new ones.
-    """
+    """List all fellowships to be able to edit them, or create new ones."""
     fellowships = Fellowship.objects.active()
 
     context = {
@@ -33,9 +31,7 @@ def fellowships(request):
 @login_required
 @permission_required('scipost.can_manage_college_composition', raise_exception=True)
 def fellowship_detail(request, id):
-    """
-    View details of a specific fellowship
-    """
+    """View details of a specific fellowship."""
     fellowship = get_object_or_404(Fellowship, id=id)
 
     context = {
diff --git a/comments/managers.py b/comments/managers.py
index c66d7f93225adf6d9e3d1883e32a118bd69f5505..dc094232df4abcdc60b907f36d6fc894af72cf17 100644
--- a/comments/managers.py
+++ b/comments/managers.py
@@ -19,3 +19,6 @@ class CommentQuerySet(models.QuerySet):
 
     def author_replies(self):
         return self.filter(is_author_reply=True)
+
+    def publicly_visible(self):
+        return self.filter(anonymous=False, status__gte=1)
diff --git a/comments/models.py b/comments/models.py
index fda1b74ae3fab6b4abb779b9b6bf09748c36fb82..23ceb52188aef09e7d162499b8e09e2a88786b4f 100644
--- a/comments/models.py
+++ b/comments/models.py
@@ -27,8 +27,10 @@ US_NOTICE = 'Warning: This field is out of service and will be removed in the fu
 
 
 class Comment(TimeStampedModel):
-    """ A Comment is an unsollicited note, submitted by a Contributor,
-    on a particular publication or in reply to an earlier Comment. """
+    """ A Comment is an unsollicited note, submitted by a Contributor.
+
+    A Comment is pointed to a particular publication or in reply to an earlier Comment. It
+    may be l"""
 
     status = models.SmallIntegerField(default=STATUS_PENDING, choices=COMMENT_STATUS)
     vetted_by = models.ForeignKey('scipost.Contributor', blank=True, null=True,
@@ -151,16 +153,16 @@ class Comment(TimeStampedModel):
             assign_perm('comments.can_vet_comments', to_object.editor_in_charge.user, self)
 
     def get_author(self):
-        '''Get author, if and only if comment is not anonymous!!!'''
+        """Return Contributor instance of object if not anonymous."""
         if not self.anonymous:
             return self.author
         return None
 
     def get_author_str(self):
-        '''Get author string, if and only if comment is not anonymous!!!'''
+        """Return author string if not anonymous."""
         author = self.get_author()
         if author:
-            return author.user.first_name + ' ' + author.user.last_name
+            return '{} {}'.format(author.get_title_display(), author.user.last_name)
         return 'Anonymous'
 
     def update_opinions(self, contributor_id, opinion):
diff --git a/comments/templates/comments/_comment_card_content.html b/comments/templates/comments/_comment_card_content.html
index fb7dff65a51631ad07bb1211b5751b85ffdb217a..6fa4f459bd55ef6e161accab805c8689b5e973b3 100644
--- a/comments/templates/comments/_comment_card_content.html
+++ b/comments/templates/comments/_comment_card_content.html
@@ -2,10 +2,11 @@
     {% block card_block_header %}{% endblock %}
     <p class="card-text">
       {% if comment.anonymous %}
-      Anonymous:
+          Anonymous:
       {% else %}
-      <a href="{{comment.author.get_absolute_url}}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a>:
+          <a href="{{ comment.author.get_absolute_url }}">{{ comment.get_author_str }}</a>:
       {% endif %}
+
         <a href="{{comment.get_absolute_url}}">
             "{{comment.comment_text|slice:'30'}}{% if comment.comment_text|length > 30 %}...{% endif %}"
         </a>
diff --git a/comments/templates/comments/_comment_card_extended_for_author.html b/comments/templates/comments/_comment_card_extended_for_author.html
index 51c26e39304d86a3b916dce310b43132f9792d83..5fa9fa5f645c02426aa4aecdc37530cb93c9b441 100644
--- a/comments/templates/comments/_comment_card_extended_for_author.html
+++ b/comments/templates/comments/_comment_card_extended_for_author.html
@@ -5,7 +5,11 @@
     </div>
 
     <p>"{{comment.comment_text|linebreaksbr}}"</p>
-    <p class="card-text">by <a href="{{comment.author.get_absolute_url}}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a> in {{comment.content_type|capfirst}} on <a href="{{comment.content_object.get_absolute_url}}" class="pubtitleli">{{comment.title}}</a> {% if comment.content_object.author_list %} <span class="text-muted">by {{comment.content_object.author_list}}</span>{% endif %}</p>
+    {% if comment.anonymous %}
+        <p class="card-text">by Anonymous in {{comment.content_type|capfirst}} on <a href="{{comment.content_object.get_absolute_url}}" class="pubtitleli">{{comment.title}}</a> {% if comment.content_object.author_list %} <span class="text-muted">by {{comment.content_object.author_list}}</span>{% endif %}</p>
+    {% else %}
+        <p class="card-text">by <a href="{{comment.author.get_absolute_url}}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a> in {{comment.content_type|capfirst}} on <a href="{{comment.content_object.get_absolute_url}}" class="pubtitleli">{{comment.title}}</a> {% if comment.content_object.author_list %} <span class="text-muted">by {{comment.content_object.author_list}}</span>{% endif %}</p>
+    {% endif %}
 
     {% comment %}
         Using 'by xxx' on non-submission comments here would be ambigious. Does the `by xxx` apply to the
diff --git a/comments/templates/comments/_comment_tex_template.html b/comments/templates/comments/_comment_tex_template.html
index cb39aa0d3c78f50d5fe9f2d75f618abadc9ce8a5..05d5e1479ade5d44ab1b41c9d15647940f1773d3 100644
--- a/comments/templates/comments/_comment_tex_template.html
+++ b/comments/templates/comments/_comment_tex_template.html
@@ -4,8 +4,8 @@ Received {{comment.date_submitted|date:'d-m-Y'}}\ \\
 {% endspaceless %}
 
 {% for subcomment in comment.nested_comments.vetted %}
-    \addcontentsline{toc}{subsection}{\protect\numberline{}{% if subcomment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.counter}} by {{subcomment.author.user.first_name}} {{subcomment.author.user.last_name}} }
+    \addcontentsline{toc}{subsection}{\protect\numberline{}{% if subcomment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.counter}} by {% if subcomment.anonymous %}Anonymous{% else %}{{subcomment.author.user.first_name}} {{subcomment.author.user.last_name}}{% endif %} }
 
-    \subsection*{ {% if subcomment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.parentloop.counter}}.{{forloop.counter}} by {{subcomment.author.user.first_name}} {{subcomment.author.user.last_name}} }
+    \subsection*{ {% if subcomment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.parentloop.counter}}.{{forloop.counter}} by {% if subcomment.anonymous %}Anonymous{% else %}{{subcomment.author.user.first_name}} {{subcomment.author.user.last_name}}{% endif %} }
     {% include 'comments/_comment_tex_template.html' with comment=subcomment %}
 {% endfor %}
diff --git a/comments/templates/partials/comments/comments_list.html b/comments/templates/partials/comments/comments_list.html
index ea3e9ac08e398d5ad273a886e34f42cd4e4f6f0d..6f35351e2a6b0e59a50c0c394113cc4040648c71 100644
--- a/comments/templates/partials/comments/comments_list.html
+++ b/comments/templates/partials/comments/comments_list.html
@@ -1,7 +1,7 @@
 {% if comments %}
     <ul class="{{ css_class|default:'' }}">
         {% for comment in comments %}
-            <li><a href="{{ comment.get_absolute_url }}"{% if target_blank %} target="_blank"{% endif %}>{% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} by {{ comment.author.get_title_display }} {{ comment.author.user.last_name }} on {{ comment.date_submitted|date:'DATE_FORMAT' }}</a></li>
+            <li><a href="{{ comment.get_absolute_url }}"{% if target_blank %} target="_blank"{% endif %}>{% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} by {{ comment.get_author_str }} on {{ comment.date_submitted|date:'DATE_FORMAT' }}</a></li>
             {% include 'partials/comments/comments_list.html' with comments=comment.nested_comments.vetted css_class='m-0 pl-4' %}
         {% endfor %}
     </ul>
diff --git a/comments/utils.py b/comments/utils.py
index 8ffa2e4fcf1b09c19ee53965ef0eae64baaa71e0..8737a8e0d20b60b23fc0f2d9e5efe4bb5a4f313c 100644
--- a/comments/utils.py
+++ b/comments/utils.py
@@ -8,7 +8,7 @@ from common.utils import BaseMailUtil
 
 
 def validate_file_extention(value, allowed_extentions):
-    '''Check if a filefield (value) has allowed extentions.'''
+    """Check if a filefield (value) has allowed extentions."""
     ext = os.path.splitext(value.name)[1]  # [0] returns path+filename
     return ext.lower() in allowed_extentions
 
@@ -19,20 +19,30 @@ class CommentUtils(BaseMailUtil):
 
     @classmethod
     def email_comment_vet_accepted_to_author(cls):
-        """
-        Send mail after Comment is vetted: `Accept`
+        """Send mail after Comment is vetted: `Accept`.
 
         Requires loading:
         comment -- Comment
         """
+        from submissions.models import Submission, Report
+
+        comment = cls._context['comment']
+        send_mail = True
+        if isinstance(comment.content_object, Submission):
+            send_mail = comment.author not in comment.content_object.authors.all()
+        elif isinstance(comment.content_object, Report):
+            send_mail = comment.author not in comment.content_object.submission.authors.all()
+
+        if not send_mail:
+            return
+
         cls._send_mail(cls, 'comment_vet_accepted',
-                       [cls._context['comment'].author.user.email],
+                       [comment.author.user.email],
                        'SciPost Comment published')
 
     @classmethod
     def email_comment_vet_rejected_to_author(cls, email_response=''):
-        """
-        Send mail after Comment is vetted: `Reject`
+        """Send mail after Comment is vetted: `Reject`.
 
         Requires loading:
         comment -- Comment
diff --git a/comments/views.py b/comments/views.py
index f916794d000fccb427ea44366310c4a58e7b11ed..69f65864535d70908d3b47e16dbfd6d06b08f6c1 100644
--- a/comments/views.py
+++ b/comments/views.py
@@ -76,10 +76,6 @@ def vet_submitted_comment(request, comment_id):
             comment.vetted_by = request.user.contributor
             comment.save()
 
-            # Send emails
-            CommentUtils.load({'comment': comment})
-            CommentUtils.email_comment_vet_accepted_to_author()
-
             # Update `latest_activity` fields
             content_object = comment.content_object
             content_object.latest_activity = timezone.now()
@@ -100,6 +96,10 @@ def vet_submitted_comment(request, comment_id):
                     SubmissionUtils.load({'submission': content_object.submission})
                     SubmissionUtils.send_author_comment_received_email()
 
+            # Send emails
+            CommentUtils.load({'comment': comment})
+            CommentUtils.email_comment_vet_accepted_to_author()
+
         elif form.cleaned_data['action_option'] == '2':
             # The comment request is simply rejected
             comment.status = int(form.cleaned_data['refusal_reason'])
diff --git a/funders/managers.py b/funders/managers.py
new file mode 100644
index 0000000000000000000000000000000000000000..12d206fbfbd2615bfca021d1b008fe64ed7197b0
--- /dev/null
+++ b/funders/managers.py
@@ -0,0 +1,12 @@
+__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.db import models
+
+
+class FunderQuerySet(models.QuerySet):
+    def has_publications(self):
+        """Return those Funder instances related to any Publication instance."""
+        return self.filter(
+            models.Q(publications__isnull=False) | models.Q(grants__publications__isnull=False))
diff --git a/funders/migrations/0003_auto_20180425_2146.py b/funders/migrations/0003_auto_20180425_2146.py
new file mode 100644
index 0000000000000000000000000000000000000000..b1f2aa55e96a7df2a9d7018efa6b6298785147d7
--- /dev/null
+++ b/funders/migrations/0003_auto_20180425_2146.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-25 19:46
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0002_auto_20171229_1435'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='funder',
+            name='acronym',
+            field=models.CharField(blank=True, default='', max_length=32),
+        ),
+    ]
diff --git a/funders/migrations/0004_auto_20180425_2146.py b/funders/migrations/0004_auto_20180425_2146.py
new file mode 100644
index 0000000000000000000000000000000000000000..a929cb51fd082773ae15c7221046270fa83be19d
--- /dev/null
+++ b/funders/migrations/0004_auto_20180425_2146.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-25 19:46
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0003_auto_20180425_2146'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='funder',
+            name='acronym',
+            field=models.CharField(blank=True, max_length=32),
+        ),
+    ]
diff --git a/funders/migrations/0005_auto_20180425_2211.py b/funders/migrations/0005_auto_20180425_2211.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ed56330406865e3630eec772710cefc37bc016b
--- /dev/null
+++ b/funders/migrations/0005_auto_20180425_2211.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-25 20:11
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0004_auto_20180425_2146'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='grant',
+            name='funder',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='grants', to='funders.Funder'),
+        ),
+        migrations.AlterField(
+            model_name='grant',
+            name='further_details',
+            field=models.CharField(blank=True, default='', max_length=256),
+        ),
+        migrations.AlterField(
+            model_name='grant',
+            name='recipient',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='grants', to='scipost.Contributor'),
+        ),
+        migrations.AlterField(
+            model_name='grant',
+            name='recipient_name',
+            field=models.CharField(blank=True, default='', max_length=64),
+        ),
+    ]
diff --git a/funders/migrations/0006_auto_20180425_2212.py b/funders/migrations/0006_auto_20180425_2212.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc846c3962a333dce84a0d59ed9f0e99a72b681f
--- /dev/null
+++ b/funders/migrations/0006_auto_20180425_2212.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-25 20:12
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0005_auto_20180425_2211'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='grant',
+            name='further_details',
+            field=models.CharField(blank=True, max_length=256),
+        ),
+        migrations.AlterField(
+            model_name='grant',
+            name='recipient_name',
+            field=models.CharField(blank=True, max_length=64),
+        ),
+    ]
diff --git a/funders/models.py b/funders/models.py
index 93410a0fe07f5e281309e0bcb32e8c84cfe761b6..ceefe67b5ec091fbfd4240e11ab90b604279bafa 100644
--- a/funders/models.py
+++ b/funders/models.py
@@ -8,16 +8,21 @@ from django.urls import reverse
 
 from journals.models import Publication
 
+from .managers import FunderQuerySet
+
 
 class Funder(models.Model):
-    """
+    """Funder is a Fundref regsitry.
+
     Funding info metadata is linked to funders from Crossref's
-    Fundref registry.
     """
+
     name = models.CharField(max_length=256)
-    acronym = models.CharField(max_length=32, blank=True, null=True)
+    acronym = models.CharField(max_length=32, blank=True)
     identifier = models.CharField(max_length=200, unique=True)
 
+    objects = FunderQuerySet.as_manager()
+
     class Meta:
         ordering = ['name', 'acronym']
 
@@ -28,27 +33,31 @@ class Funder(models.Model):
         return result
 
     def get_absolute_url(self):
+        """Return the Funder detail page."""
         return reverse('funders:funder_publications', args=(self.id,))
 
     def all_related_publications(self):
+        """Return all Publication objects linked to this Funder."""
         return Publication.objects.filter(
             Q(funders_generic=self) | Q(grants__funder=self)).distinct()
 
 
 class Grant(models.Model):
-    """
-    An instance of a grant, award or other funding.
+    """An instance of a grant, award or other funding.
+
     In a Publication's metadata, all grants are listed
     in the Crossmark part of the metadata.
     """
+
     funder = models.ForeignKey('funders.Funder', on_delete=models.CASCADE)
     number = models.CharField(max_length=64)
-    recipient_name = models.CharField(max_length=64, blank=True, null=True)
+    recipient_name = models.CharField(max_length=64, blank=True)
     recipient = models.ForeignKey('scipost.Contributor', blank=True, null=True,
                                   on_delete=models.CASCADE)
-    further_details = models.CharField(max_length=256, blank=True, null=True)
+    further_details = models.CharField(max_length=256, blank=True)
 
     class Meta:
+        default_related_name = 'grants'
         ordering = ['funder', 'recipient', 'recipient_name', 'number']
         unique_together = ('funder', 'number')
 
diff --git a/funders/templates/funders/base.html b/funders/templates/funders/base.html
new file mode 100644
index 0000000000000000000000000000000000000000..b36e0fc49f13e65cb6024b6183a05889f0f4c8fa
--- /dev/null
+++ b/funders/templates/funders/base.html
@@ -0,0 +1,13 @@
+{% extends 'scipost/base.html' %}
+
+{% block breadcrumb %}
+    <div class="container-outside header">
+        <div class="container">
+            <nav class="breadcrumb hidden-sm-down">
+                {% block breadcrumb_items %}
+                    <a href="{% url 'funders:funders' %}" class="breadcrumb-item">Funders</a>
+                {% endblock %}
+            </nav>
+        </div>
+    </div>
+{% endblock %}
diff --git a/funders/templates/funders/funder_details.html b/funders/templates/funders/funder_details.html
index 382cb69bb5ec80832975e65ba26e9bf61f000bd5..9fd9b51b26bfd08ea977e54263ef1a86d481b053 100644
--- a/funders/templates/funders/funder_details.html
+++ b/funders/templates/funders/funder_details.html
@@ -1,16 +1,25 @@
-{% extends 'scipost/base.html' %}
+{% extends 'funders/base.html' %}
 
 {% block pagetitle %}: Funder details{% endblock pagetitle %}
 
+{% block breadcrumb_items %}
+    {{ block.super }}
+    <span class="breadcrumb-item">{{ funder.name }}</span>
+{% endblock %}
+
 {% block content %}
 
 <h1 class="highlight">Funder {{ funder.name }}</h1>
 
 
-<h3>All Publications related to this Funder</h3>
+<h3>All Publications related to {{ funder.name }}</h3>
 <ul>
     {% for publication in funder.all_related_publications %}
-        <li><a href="{{ publication.get_absolute_url }}">{{ publication }}</a></li>
+        <li>
+            <a href="{{ publication.get_absolute_url }}">{{ publication.title }}</a>
+            <br>by {{ publication.author_list }},
+            <br>{{ publication.citation }}
+        </li>
     {% empty %}
         <li>No publications</li>
     {% endfor %}
diff --git a/funders/templates/funders/funder_list.html b/funders/templates/funders/funder_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..ac4b9599470ee692c81d348970595963f9d90198
--- /dev/null
+++ b/funders/templates/funders/funder_list.html
@@ -0,0 +1,29 @@
+{% extends 'funders/base.html' %}
+
+{% block pagetitle %}: Funders list{% endblock pagetitle %}
+
+{% block breadcrumb_items %}
+    <span class="breadcrumb-item">Funders</span>
+{% endblock %}
+
+{% block content %}
+
+<h1 class="highlight">Funders</h1>
+
+{% if perms.scipost.can_view_all_funding_info %}
+    <a href="{% url 'funders:funders_dashboard' %}">Go to dashboard</a>
+    <br><br>
+{% endif %}
+
+<h3>All Funders with a SciPost publication</h3>
+
+<ul>
+    {% for funder in funders %}
+        <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li>
+    {% empty %}
+        <li>No funders</li>
+    {% endfor %}
+</ul>
+
+
+{% endblock content %}
diff --git a/funders/templates/funders/funders.html b/funders/templates/funders/funders_dashboard.html
similarity index 94%
rename from funders/templates/funders/funders.html
rename to funders/templates/funders/funders_dashboard.html
index 0ab70cf7f9e3769407ee16b5fbf14ef0765ac7d9..16ea8e04a2b36caa4767ce575c9196d6126a1492 100644
--- a/funders/templates/funders/funders.html
+++ b/funders/templates/funders/funders_dashboard.html
@@ -1,6 +1,11 @@
-{% extends 'scipost/base.html' %}
+{% extends 'funders/base.html' %}
 
-{% block pagetitle %}: Funders{% endblock pagetitle %}
+{% block pagetitle %}: Funders dashboard{% endblock pagetitle %}
+
+{% block breadcrumb_items %}
+    {{ block.super }}
+    <span class="breadcrumb-item">Dashboard</span>
+{% endblock %}
 
 {% load bootstrap %}
 
diff --git a/funders/urls.py b/funders/urls.py
index 8ec6892cddbbc9a46582790535020b16c2f04190..48f99d288374cd7faded49940a731a2604568833 100644
--- a/funders/urls.py
+++ b/funders/urls.py
@@ -8,10 +8,10 @@ from . import views
 
 urlpatterns = [
     url(r'^$', views.funders, name='funders'),
+    url(r'^dashboard$', views.funders_dashboard, name='funders_dashboard'),
     url(r'^query_crossref_for_funder$', views.query_crossref_for_funder,
         name='query_crossref_for_funder'),
     url(r'^add$', views.add_funder, name='add_funder'),
-    url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications,
-        name='funder_publications'),
+    url(r'^(?P<funder_id>[0-9]+)/$', views.funder_publications, name='funder_publications'),
     url(r'^grants/add$', views.CreateGrantView.as_view(), name='add_grant'),
 ]
diff --git a/funders/views.py b/funders/views.py
index 5e04d384fe374d608c3fe868ce0255d17307527d..f6b2d5b56af91fda9bcfe07df1596e76cfc660cb 100644
--- a/funders/views.py
+++ b/funders/views.py
@@ -20,14 +20,15 @@ from scipost.mixins import PermissionsMixin
 
 
 @permission_required('scipost.can_view_all_funding_info', raise_exception=True)
-def funders(request):
+def funders_dashboard(request):
+    """Administration of Funders and Grants."""
     funders = Funder.objects.all()
     form = FunderRegistrySearchForm()
     grants = Grant.objects.all()
     grant_form = GrantForm(request=request)
     context = {'form': form, 'funders': funders,
                'grants': grants, 'grant_form': grant_form}
-    return render(request, 'funders/funders.html', context)
+    return render(request, 'funders/funders_dashboard.html', context)
 
 
 @permission_required('scipost.can_view_all_funding_info', raise_exception=True)
@@ -59,13 +60,20 @@ def add_funder(request):
                          str(funder))
     elif form.has_changed():
         messages.warning(request, 'The form was invalidly filled.')
-    return redirect(reverse('funders:funders'))
+    return redirect(reverse('funders:funders_dashboard'))
+
+
+def funders(request):
+    """List page of Funders."""
+    funders = Funder.objects.has_publications().distinct()
+    context = {
+        'funders': funders
+    }
+    return render(request, 'funders/funder_list.html', context)
 
 
 def funder_publications(request, funder_id):
-    """
-    See details of specific Funder (publicly accessible).
-    """
+    """Detail page of a specific Funder (publicly accessible)."""
     funder = get_object_or_404(Funder, id=funder_id)
     context = {'funder': funder}
     return render(request, 'funders/funder_details.html', context)
@@ -91,4 +99,4 @@ class CreateGrantView(PermissionsMixin, HttpRefererMixin, CreateView):
     permission_required = 'scipost.can_create_grants'
     model = Grant
     form_class = GrantForm
-    success_url = reverse_lazy('funders:funders')
+    success_url = reverse_lazy('funders:funders_dashboard')
diff --git a/invitations/admin.py b/invitations/admin.py
index 59092e3c025f2d394d3a28100190ff2402eedb37..068ed5f3598d9def5645964aa8ae308ec7d23f64 100644
--- a/invitations/admin.py
+++ b/invitations/admin.py
@@ -20,7 +20,7 @@ admin.site.register(RegistrationInvitation, RegistrationInvitationAdmin)
 class CitationNotificationAdmin(admin.ModelAdmin):
     date_hierarchy = 'date_sent'
     search_fields = ['invitation__first_name', 'invitation__last_name',
-                     'contributor__first_name', 'contributor__last_name']
+                     'contributor__user__first_name', 'contributor__user__last_name']
     list_display = ['__str__', 'created_by', 'date_sent', 'processed']
     list_filter = ['processed']
 
diff --git a/invitations/forms.py b/invitations/forms.py
index 98da5c53684c3ff8be40188af9990244f8331d8b..d3e299992bed5d5fbc0147f778647042e8389e41 100644
--- a/invitations/forms.py
+++ b/invitations/forms.py
@@ -126,6 +126,66 @@ class RegistrationInvitationAddCitationForm(AcceptRequestMixin, forms.ModelForm)
         return self.instance
 
 
+class RegistrationInvitationMergeForm(AcceptRequestMixin, forms.ModelForm):
+    """Merge RegistrationInvitations.
+
+    This form will merge the instance with any other RegistrationInvitation selected
+    into a single RegistrationInvitation.
+    """
+
+    invitation = forms.ModelChoiceField(queryset=RegistrationInvitation.objects.none(),
+                                        label="Invitation to merge with")
+
+    class Meta:
+        model = RegistrationInvitation
+        fields = ()
+
+    def __init__(self, *args, **kwargs):
+        """Update queryset according to the passed instance."""
+        super().__init__(*args, **kwargs)
+        self.fields['invitation'].queryset = RegistrationInvitation.objects.no_response().filter(
+            last_name__icontains=self.instance.last_name).exclude(id=self.instance.id)
+
+    def save(self, *args, **kwargs):
+        """Merge the two RegistationInvitations into one."""
+        if kwargs.get('commit', True):
+            # Pick the right Invitation, with the most up-to-date invitation_key
+            selected_invitation = self.cleaned_data['invitation']
+            if not selected_invitation.date_sent_last:
+                # Selected Invitation has never been sent yet.
+                leading_invitation = self.instance
+                deprecated_invitation = selected_invitation
+            elif not self.instance.date_sent_last:
+                # Instance has never been sent yet.
+                leading_invitation = selected_invitation
+                deprecated_invitation = self.instance
+            elif selected_invitation.date_sent_last > self.instance.date_sent_last:
+                # Lastest reminder: selected Invitation
+                leading_invitation = selected_invitation
+                deprecated_invitation = self.instance
+            else:
+                # Lastest reminder: instance
+                leading_invitation = self.instance
+                deprecated_invitation = selected_invitation
+
+            # Move CitationNotification to the new leading Invitation
+            deprecated_invitation.citation_notifications.update(invitation=leading_invitation)
+            leading_invitation.times_sent += deprecated_invitation.times_sent   # Update counts
+            leading_invitation.save()
+
+            qs_contributor = deprecated_invitation.citation_notifications.filter(
+                contributor__isnull=False).values_list('contributor', flat=True)
+            if qs_contributor:
+                if not leading_invitation.citation_notifications.filter(contributor__isnull=False):
+                    # Contributor is already assigned in "old" RegistrationInvitation, copy it.
+                    leading_invitation.citation_notifications.filter(contributor=qs_contributor[0])
+
+            # Magic.
+            deprecated_invitation.delete()
+        return self.instance
+
+
+
 class RegistrationInvitationForm(AcceptRequestMixin, forms.ModelForm):
     cited_in_submissions = AutoCompleteSelectMultipleField('submissions_lookup', required=False)
     cited_in_publications = AutoCompleteSelectMultipleField('publication_lookup', required=False)
diff --git a/invitations/migrations/0013_auto_20180414_2053.py b/invitations/migrations/0013_auto_20180414_2053.py
new file mode 100644
index 0000000000000000000000000000000000000000..8537b33a834a5aba7e52c4f69a5f36901b36828d
--- /dev/null
+++ b/invitations/migrations/0013_auto_20180414_2053.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-14 18:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('invitations', '0012_auto_20180220_2120'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='citationnotification',
+            name='invitation',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='citation_notifications', to='invitations.RegistrationInvitation'),
+        ),
+    ]
diff --git a/invitations/models.py b/invitations/models.py
index fc42000e0066051c1b2372bc44f7f923fa8839e0..9d1a8b8b5f687cab32aef07255f54f3bec428db1 100644
--- a/invitations/models.py
+++ b/invitations/models.py
@@ -98,7 +98,7 @@ class RegistrationInvitation(models.Model):
 
 class CitationNotification(models.Model):
     invitation = models.ForeignKey('invitations.RegistrationInvitation',
-                                   on_delete=models.SET_NULL,
+                                   on_delete=models.CASCADE,
                                    null=True, blank=True)
     contributor = models.ForeignKey('scipost.Contributor',
                                     on_delete=models.CASCADE,
diff --git a/invitations/templates/invitations/registrationinvitation_form_merge.html b/invitations/templates/invitations/registrationinvitation_form_merge.html
new file mode 100644
index 0000000000000000000000000000000000000000..3c284b5102cc9c3a5a7c25e9feeba03adf52da0c
--- /dev/null
+++ b/invitations/templates/invitations/registrationinvitation_form_merge.html
@@ -0,0 +1,34 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block pagetitle %}: Edit Registration Invitation{% endblock pagetitle %}
+
+{% load scipost_extras %}
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <a href="{% url 'invitations:list' %}" class="breadcrumb-item">Registration Invitations</a>
+    <span class="breadcrumb-item">Edit</span>
+{% endblock %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Registration Invitation {{ object.id }}</h1>
+        {% include 'partials/invitations/registrationinvitation_summary.html' with invitation=object %}
+
+        <form method="post">
+            {% csrf_token %}
+            {{ form|bootstrap }}
+            <button type="submit" class="btn btn-primary" name="save" value="save">Merge</button>
+        </form>
+    </div>
+</div>
+
+{% endblock %}
+
+{% block footer_script %}
+    {{ block.super }}
+    {{ form.media }}
+{% endblock footer_script %}
diff --git a/invitations/templates/partials/invitations/registrationinvitation_table.html b/invitations/templates/partials/invitations/registrationinvitation_table.html
index 1e85df48e5d4567cac19a3196e23f34ea2d32f2b..86ac4b72bca1963997f2cb59f82c325da7eb702d 100644
--- a/invitations/templates/partials/invitations/registrationinvitation_table.html
+++ b/invitations/templates/partials/invitations/registrationinvitation_table.html
@@ -53,6 +53,7 @@
                             </li>
                         {% endfor %}
                         <li><a href="{% url 'invitations:add_citation' invitation.id %}">Add new Citation to Invitation</a></li>
+                        <li><a href="{% url 'invitations:merge' invitation.id %}">Merge this Invitation</a></li>
                     </ul>
                 </td>
             {% else %}
diff --git a/invitations/urls.py b/invitations/urls.py
index 5f69269f97c6686a4b19c097d58a38c5eac72124..3761e3a75cde19c91c7fa17c2b9fdf5adf48a072 100644
--- a/invitations/urls.py
+++ b/invitations/urls.py
@@ -8,7 +8,7 @@ from . import views
 
 urlpatterns = [
     url(r'^$', views.RegistrationInvitationsView.as_view(), name='list'),
-    url(r'^sent$', views.RegistrationInvitationsSentView.as_view(), name='list_sent'),
+    url(r'^sent$', views.RegistrationInvitationsSendView.as_view(), name='list_sent'),
     url(r'^fellows$', views.RegistrationInvitationsFellowView.as_view(), name='list_fellows'),
     url(r'^new$', views.create_registration_invitation_or_citation, name='new'),
     url(r'^(?P<pk>[0-9]+)/$', views.RegistrationInvitationsUpdateView.as_view(), name='update'),
@@ -16,6 +16,8 @@ urlpatterns = [
         name='add_citation'),
     url(r'^(?P<pk>[0-9]+)/delete$', views.RegistrationInvitationsDeleteView.as_view(),
         name='delete'),
+    url(r'^(?P<pk>[0-9]+)/merge$', views.RegistrationInvitationsMergeView.as_view(),
+        name='merge'),
     url(r'^(?P<pk>[0-9]+)/mark/(?P<label>sent)$', views.RegistrationInvitationsMarkView.as_view(),
         name='mark'),
     url(r'^(?P<pk>[0-9]+)/map_to_contributor/(?P<contributor_id>[0-9]+)/$',
diff --git a/invitations/views.py b/invitations/views.py
index 3caa687f791cdd794f04df1d860c29ebef9f7fa0..d54c002300f5b2aa41fa581f72cb5a44303bface 100644
--- a/invitations/views.py
+++ b/invitations/views.py
@@ -13,7 +13,8 @@ from django.views.generic.edit import UpdateView, DeleteView
 from .forms import RegistrationInvitationForm, RegistrationInvitationReminderForm,\
     RegistrationInvitationMarkForm, RegistrationInvitationMapToContributorForm,\
     CitationNotificationForm, SuggestionSearchForm, RegistrationInvitationFilterForm,\
-    CitationNotificationProcessForm, RegistrationInvitationAddCitationForm
+    CitationNotificationProcessForm, RegistrationInvitationAddCitationForm,\
+    RegistrationInvitationMergeForm
 from .mixins import RequestArgumentMixin, SaveAndSendFormMixin, SendMailFormMixin
 from .models import RegistrationInvitation, CitationNotification
 
@@ -43,8 +44,8 @@ class RegistrationInvitationsView(PaginationMixin, PermissionsMixin, ListView):
         return context
 
 
-class RegistrationInvitationsSentView(RegistrationInvitationsView):
-    permission_required = 'scipost.can_create_registration_invitations'
+class RegistrationInvitationsSendView(RegistrationInvitationsView):
+    permission_required = 'scipost.can_manage_registration_invitations'
     queryset = RegistrationInvitation.objects.sent().not_for_fellows()
     template_name = 'invitations/registrationinvitation_list_sent.html'
 
@@ -162,6 +163,14 @@ class RegistrationInvitationsUpdateView(RequestArgumentMixin, PermissionsMixin,
         return qs
 
 
+class RegistrationInvitationsMergeView(RequestArgumentMixin, PermissionsMixin, UpdateView):
+    permission_required = 'scipost.can_manage_registration_invitations'
+    queryset = RegistrationInvitation.objects.no_response()
+    form_class = RegistrationInvitationMergeForm
+    template_name = 'invitations/registrationinvitation_form_merge.html'
+    success_url = reverse_lazy('invitations:list')
+
+
 class RegistrationInvitationsAddCitationView(RequestArgumentMixin, PermissionsMixin, UpdateView):
     permission_required = 'scipost.can_create_registration_invitations'
     form_class = RegistrationInvitationAddCitationForm
diff --git a/journals/migrations/0027_auto_20180414_2053.py b/journals/migrations/0027_auto_20180414_2053.py
new file mode 100644
index 0000000000000000000000000000000000000000..165078a172a03bde9e214369a8d6f04226dcd2ef
--- /dev/null
+++ b/journals/migrations/0027_auto_20180414_2053.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-14 18:53
+from __future__ import unicode_literals
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0026_auto_20180327_1937'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='publication',
+            name='doi_label',
+            field=models.CharField(db_index=True, max_length=200, unique=True, validators=[django.core.validators.RegexValidator('^(SciPostPhysProc|SciPostPhysSel|SciPostPhysLectNotes|SciPostPhys).[0-9]+(.[0-9]+.[0-9]{3,})?$', 'Only valid DOI expressions are allowed (`[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,}` or `[a-zA-Z]+.[0-9]+`)')]),
+        ),
+    ]
diff --git a/journals/templates/journals/journals.html b/journals/templates/journals/journals.html
index a696b5cd0184ce4be0100e0afae9a8c1dbcf23cd..2dad808af08ed6a0f3266302465db2b77a04aab4 100644
--- a/journals/templates/journals/journals.html
+++ b/journals/templates/journals/journals.html
@@ -69,13 +69,6 @@
 </div>
 
 <div class="row">
-    <div class="col-md-6">
-        <h1 class="banner">SciPost Physics Select</h1>
-        <div class="py-2">
-            <p>SciPost Physics Select publishes articles of superlative quality in the field of Physics.</p>
-            <p>Authors cannot submit directly to this Journal; SPS papers are editorially selected from the most outstanding Submissions to SciPost Physics.</p>
-        </div>
-    </div>
     <div class="col-md-6">
         <h1 class="banner"><a href="{% url 'scipost:landing_page' 'SciPostPhysLectNotes' %}">SciPost Physics Lecture Notes</a></h1>
         <div class="py-2">
diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html
index bcaa4e0c9daaf8e0c5ddaf74f95195bfdb1f4327..0d240c96c2169ffb44cecf3df8ee4ade5f474373 100644
--- a/journals/templates/journals/manage_metadata.html
+++ b/journals/templates/journals/manage_metadata.html
@@ -150,7 +150,7 @@ event: "focusin"
 	    <br/>
 	    <h3>Other funding-related actions:</h3>
 	    <ul>
-	      <li><a href="{% url 'funders:funders' %}" target="_blank">go to the Funders page to add a Funder and/or Grant instance</a></li>
+	      <li><a href="{% url 'funders:funders_dashboard' %}" target="_blank">go to the Funders page to add a Funder and/or Grant instance</a></li>
 	    </ul>
 	  </div>
 	</div>
diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html
index 67892330e77d5b979ec472bfd0b120cc4136fc55..9566a22849031cf93121803010d500cfd1808d0e 100644
--- a/journals/templates/journals/publication_detail.html
+++ b/journals/templates/journals/publication_detail.html
@@ -107,30 +107,22 @@
                 {% endfor %}
             </ul>
 
+            {% if publication.funders_generic.all %}
+                <h3>Funder{{ publication.funders_generic.count|pluralize }} for this publication</h3>
+                <ul>
+                    {% for funder in publication.funders_generic.all %}
+                        <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li>
+                    {% endfor %}
+                </ul>
+            {% endif %}
 
-
-            {% if is_edcol_admin %}
-                {# This function is not available for public yet! #}
-                <em>The following is not available for the public yet:</em>
-                {% include 'partials/journals/references.html' with publication=publication %}
-
-                {% if publication.funders_generic.exists %}
-                    <h3>Funder{{ publication.funders_generic.count|pluralize }} for this publication:</h3>
-                    <ul>
-                        {% for funder in publication.funders_generic.all %}
-                            <li><a href="{{ funder.get_absolute_url }}">{{ funder }}</a></li>
-                        {% endfor %}
-                    </ul>
-                {% endif %}
-
-                {% if publication.institutions.exists %}
-                    <h3>Institution{{ publication.institutions.count|pluralize }} related to this Publication:</h3>
-                    <ul>
-                        {% for institution in publication.institutions.all %}
-                            <li>{{ institution }}</li>
-                        {% endfor %}
-                    </ul>
-                {% endif %}
+            {% if publication.institutions.all %}
+                <h3>Institution{{ publication.institutions.count|pluralize }} related to this Publication</h3>
+                <ul>
+                    {% for institution in publication.institutions.all %}
+                        <li><a href="{{ institution.get_absolute_url }}">{{ institution }}</a></li>
+                    {% endfor %}
+                </ul>
             {% endif %}
         </div>
     </div>
diff --git a/journals/views.py b/journals/views.py
index a0aec70a3a39d85dec00399cedb61fea24bed4e5..a5fee852fb4deb606f67f47e472de14bb46f6a17 100644
--- a/journals/views.py
+++ b/journals/views.py
@@ -1152,6 +1152,6 @@ def arxiv_doi_feed(request, doi_label):
     for publication in publications:
         feedxml += ('\n<article preprint_id="%s" doi="%s" journal_ref="%s" />' % (
             publication.accepted_submission.arxiv_identifier_wo_vn_nr, publication.doi_string,
-            publication.citation()))
+            publication.citation))
     feedxml += '\n</preprint>'
     return HttpResponse(feedxml, content_type='text/xml')
diff --git a/mailing_lists/models.py b/mailing_lists/models.py
index 5d6bdfe0d80e987b1ade7a7afa459288cc54f5d5..e9ccc0b32da6c800d3179cda24d3a3adb32cc709 100644
--- a/mailing_lists/models.py
+++ b/mailing_lists/models.py
@@ -17,7 +17,7 @@ from .constants import MAIL_LIST_STATUSES, MAIL_LIST_STATUS_ACTIVE,\
 from .managers import MailListManager
 
 from scipost.behaviors import TimeStampedModel
-from scipost.constants import CONTRIBUTOR_NORMAL
+from scipost.constants import NORMAL_CONTRIBUTOR
 from scipost.models import Contributor
 
 
@@ -88,7 +88,7 @@ class MailchimpList(TimeStampedModel):
         # are not in the list yet.
         db_subscribers = (User.objects
                           .filter(contributor__isnull=False)
-                          .filter(is_active=True, contributor__status=CONTRIBUTOR_NORMAL)
+                          .filter(is_active=True, contributor__status=NORMAL_CONTRIBUTOR)
                           .filter(contributor__accepts_SciPost_emails=True,
                                   groups__in=self.allowed_groups.all(),
                                   email__isnull=False,
diff --git a/mails/templates/mail_templates/registration_invitation.html b/mails/templates/mail_templates/registration_invitation.html
index fceaa5f9956115a983731e522ee8a74e28fb4f16..beae41fdc428089bb93649de69e6512c273eeac2 100644
--- a/mails/templates/mail_templates/registration_invitation.html
+++ b/mails/templates/mail_templates/registration_invitation.html
@@ -80,7 +80,7 @@ Dear {% if invitation.message_style == 'F' %}{{ invitation.get_title_display }}
         </ul>
     {% endif %}
     <p>
-        I would hereby like to use this opportunity to quickly introduce you to the SciPost initiative, and to invite you to become an active Contributor.
+        We would hereby like to use this opportunity to quickly introduce you to the SciPost initiative, and to invite you to become an active Contributor.
     </p>
     <p>
         In summary, SciPost.org is a publication portal managed by
@@ -115,10 +115,12 @@ Dear {% if invitation.message_style == 'F' %}{{ invitation.get_title_display }}
     <p>
         Many thanks in advance for taking a few minutes to look into it,
         <br>
-        On behalf of the SciPost Foundation,
-        <br>
-        <br>
-        {{ invitation.invited_by.contributor.get_title_display }} {{ invitation.invited_by.first_name }} {{ invitation.invited_by.last_name }}
+        <br>SciPost Foundation
+        <br>Institute for Theoretial Physics
+        <br>University of Amsterdam
+        <br>Science Park 904
+        <br>1098 XH Amsterdam
+        <br>The Netherlands
     </p>
 {% elif invitation.invitation_type == 'F' %}
     {# Fellow invite #}
diff --git a/mails/templates/mail_templates/submissions_assignment_failed.html b/mails/templates/mail_templates/submissions_assignment_failed.html
new file mode 100644
index 0000000000000000000000000000000000000000..382b4217405c28280daa788d592d42fab903fd3c
--- /dev/null
+++ b/mails/templates/mail_templates/submissions_assignment_failed.html
@@ -0,0 +1,17 @@
+<p>Dear {{ submission.submitted_by.get_title_display }} {{ submission.submitted_by.user.last_name }},</p>
+<p>Your recent Submission to SciPost,</p>
+<p>{{ submission.title }}</p>
+<p>by {{ submission.author_list }}</p>
+<p>
+    has unfortunately not passed the pre-screening stage.
+    We therefore regret to inform you that we will not
+    process your paper further towards publication, and that you
+    are now free to send your manuscript to an alternative journal.
+</p>
+
+
+<p>We nonetheless thank you very much for your contribution.</p>
+<p>Sincerely,</p>
+<p>The SciPost Team.</p>
+
+{% include 'email/_footer.html' %}
diff --git a/mails/templates/mail_templates/submissions_assignment_failed.json b/mails/templates/mail_templates/submissions_assignment_failed.json
new file mode 100644
index 0000000000000000000000000000000000000000..9b1051a0bc9cdfdbf1e524a93326f6e2f45b55fd
--- /dev/null
+++ b/mails/templates/mail_templates/submissions_assignment_failed.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: pre-screening not passed",
+    "to_address": "submitted_by.user.email",
+    "bcc_to": "submissions@scipost.org",
+    "from_address_name": "SciPost Editorial Admin",
+    "from_address": "submissions@scipost.org",
+    "context_object": "submission"
+}
diff --git a/mails/templates/mails/mail_form.html b/mails/templates/mails/mail_form.html
index f1afc1a879536a84a3fe69de45cb7930ce025d19..6bae596d97c8f88e000f6f83829e5c554c974e64 100644
--- a/mails/templates/mails/mail_form.html
+++ b/mails/templates/mails/mail_form.html
@@ -6,7 +6,13 @@
 
 {% block content %}
 
-    <h1>Complete and send mail</h1>
+    {% if header_template %}
+        {% include header_template with object=object %}
+        <hr class="divider">
+        <h2 class="highlight">Complete and send mail</h2>
+    {% else %}
+        <h1 class="highlight">Complete and send mail</h1>
+    {% endif %}
     <h3 class="mb-4">You may edit the mail before sending it.</h3>
 
     <form enctype="multipart/form-data" method="post">
diff --git a/mails/views.py b/mails/views.py
index 6132d392342310e7dff63ef38295450998d5f0f7..36578a74a7baa349e13f3a40723c0ff63ae61cc4 100644
--- a/mails/views.py
+++ b/mails/views.py
@@ -15,6 +15,7 @@ class MailEditingSubView(object):
         self.request = request
         self.context = kwargs.get('context', {})
         self.template_name = kwargs.get('template', 'mails/mail_form.html')
+        self.header_template = kwargs.get('header_template', '')
         self.mail_form = EmailTemplateForm(request.POST or None, mail_code=mail_code, **kwargs)
 
     @property
@@ -38,6 +39,11 @@ class MailEditingSubView(object):
 
     def return_render(self):
         self.context['form'] = self.mail_form
+        self.context['header_template'] = self.header_template
+        if hasattr(self.mail_form, 'instance') and self.mail_form.instance:
+            self.context['object'] = self.mail_form.instance
+        else:
+            self.context['object'] = None
         return render(self.request, self.template_name, self.context)
 
 
diff --git a/mails/widgets.py b/mails/widgets.py
index f9cfaf114b35723693da4d54e6d187cd2967829a..d13bcf86bc4f2a7111d0cfc96f5d0e5af5ab4f53 100644
--- a/mails/widgets.py
+++ b/mails/widgets.py
@@ -52,9 +52,8 @@ class SummernoteEditor(widgets.Textarea):
     def trigger_summernote(self, el_id, options):
         str = """
         <script type='text/javascript'>
-            var $ = jQuery;
-            $(document).ready(function() {
-                $('#%s').summernote(%s)
+            $(function() {
+                $('#%s').summernote(%s);
             });
         </script>""" % (el_id, options)
         return str
@@ -66,7 +65,7 @@ class SummernoteEditor(widgets.Textarea):
         }
         js = ('//cdnjs.cloudflare.com/ajax/libs/summernote/0.8.8/summernote-bs4.js',)
 
-        if self.include_jquery:
-            js = ('//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js',) + js
+        # if self.include_jquery:
+        #     js = ('//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js',) + js
 
         return Media(css=css, js=js)
diff --git a/notifications/templates/notifications/partials/notification_list_popover.html b/notifications/templates/notifications/partials/notification_list_popover.html
index 89f08094fdb87affd7f7d7f830c5695c988ffe0a..3f16c462650a4c636afde7c90ebd8d78bf609d74 100644
--- a/notifications/templates/notifications/partials/notification_list_popover.html
+++ b/notifications/templates/notifications/partials/notification_list_popover.html
@@ -31,7 +31,7 @@
             {% endif %}
 
             {% if perms.scipost.can_view_all_funding_info %}
-                <a class="item {% active 'funders:funders' %}" href="{% url 'funders:funders' %}">Funders</a>
+                <a class="item {% active 'funders:funders_dashboard' %}" href="{% url 'funders:funders_dashboard' %}">Funders</a>
             {% endif %}
 
             {% if perms.scipost.can_view_production %}
diff --git a/partners/models.py b/partners/models.py
index 966a782317001e39eb221f954b9a3b4e03110657..d8c0b21da83faa3fade57d4fcbbf8ffd902c07f7 100644
--- a/partners/models.py
+++ b/partners/models.py
@@ -14,22 +14,20 @@ from django.urls import reverse
 
 from django_countries.fields import CountryField
 
-from .constants import PARTNER_KINDS, PARTNER_STATUS, CONSORTIUM_STATUS, MEMBERSHIP_DURATION,\
-                       PROSPECTIVE_PARTNER_STATUS, PROSPECTIVE_PARTNER_EVENTS, PARTNER_EVENTS,\
-                       MEMBERSHIP_AGREEMENT_STATUS, PROSPECTIVE_PARTNER_ADDED,\
-                       PARTNER_KIND_UNI_LIBRARY
-from .constants import PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT,\
-                       PROSPECTIVE_PARTNER_APPROACHED,\
-                       PROSPECTIVE_PARTNER_EVENT_INITIATE_NEGOTIATION,\
-                       PROSPECTIVE_PARTNER_NEGOTIATING,\
-                       PROSPECTIVE_PARTNER_EVENT_MARKED_AS_UNINTERESTED,\
-                       PROSPECTIVE_PARTNER_UNINTERESTED,\
-                       PROSPECTIVE_PARTNER_EVENT_PROMOTED,\
-                       PROSPECTIVE_PARTNER_PROCESSED, CONTACT_TYPES,\
-                       PARTNER_INITIATED, REQUEST_STATUSES, REQUEST_INITIATED
-
-from .managers import MembershipAgreementManager, ProspectivePartnerManager, PartnerManager,\
-                      ContactRequestManager, PartnersAttachmentManager
+from .constants import (
+    PARTNER_KINDS, PARTNER_STATUS, CONSORTIUM_STATUS, MEMBERSHIP_DURATION, PARTNER_EVENTS,
+    PROSPECTIVE_PARTNER_STATUS, PROSPECTIVE_PARTNER_EVENTS, MEMBERSHIP_AGREEMENT_STATUS,
+    PROSPECTIVE_PARTNER_ADDED, PARTNER_KIND_UNI_LIBRARY)
+from .constants import (
+    PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT, PROSPECTIVE_PARTNER_APPROACHED, PARTNER_INITIATED,
+    PROSPECTIVE_PARTNER_EVENT_INITIATE_NEGOTIATION, PROSPECTIVE_PARTNER_PROCESSED, CONTACT_TYPES,
+    PROSPECTIVE_PARTNER_NEGOTIATING, PROSPECTIVE_PARTNER_EVENT_MARKED_AS_UNINTERESTED,
+    REQUEST_STATUSES, PROSPECTIVE_PARTNER_UNINTERESTED, PROSPECTIVE_PARTNER_EVENT_PROMOTED,
+    REQUEST_INITIATED)
+
+from .managers import (
+    MembershipAgreementManager, ProspectivePartnerManager, PartnerManager, ContactRequestManager,
+    PartnersAttachmentManager)
 
 from scipost.constants import TITLE_CHOICES
 from scipost.fields import ChoiceArrayField
@@ -44,9 +42,8 @@ now = timezone.now()
 ########################
 
 class ProspectivePartner(models.Model):
-    """
-    Created from the membership_request page, after submitting a query form.
-    """
+    """A prospect Partner is a Partner without explicit contract with SciPost yet."""
+
     kind = models.CharField(max_length=32, choices=PARTNER_KINDS, default=PARTNER_KIND_UNI_LIBRARY)
     institution_name = models.CharField(max_length=256)
     country = CountryField()
@@ -62,6 +59,11 @@ class ProspectivePartner(models.Model):
                                          self.date_received.strftime("%Y-%m-%d"),
                                          self.get_status_display())
 
+    @property
+    def is_promoted_to_partner(self):
+        """Check if Prospect is already known to be a Partner."""
+        return self.status == PROSPECTIVE_PARTNER_PROCESSED
+
     def update_status_from_event(self, event):
         if event == PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT:
             self.status = PROSPECTIVE_PARTNER_APPROACHED
diff --git a/partners/templates/partners/_prospective_partner_card.html b/partners/templates/partners/_prospective_partner_card.html
index 48c903504c317ae88d07ef63fdbd60c621bbd770..9a56f10cd941f5f431d31d4735cacc6ce8ea2402 100644
--- a/partners/templates/partners/_prospective_partner_card.html
+++ b/partners/templates/partners/_prospective_partner_card.html
@@ -70,10 +70,12 @@
         <input type="submit" name="submit" value="Submit" class="btn btn-outline-secondary">
       </form>
 
-      <h3>Partner status</h3>
-      <ul>
-          <li><a href="{% url 'partners:promote_prospartner' pp.id %}">Upgrade prospect to partner</a></li>
-      </ul>
+      {% if not pp.is_promoted_to_partner %}
+          <h3>Partner status</h3>
+          <ul>
+              <li><a href="{% url 'partners:promote_prospartner' pp.id %}">Upgrade prospect to partner</a></li>
+          </ul>
+      {% endif %}
     </div>
   </div>
 </div>
diff --git a/partners/views.py b/partners/views.py
index a17405729386aea2af58cb53b24854e185c9e4d0..9c5bf531d0eddab20e19d08ebb22f4480caff132 100644
--- a/partners/views.py
+++ b/partners/views.py
@@ -47,10 +47,11 @@ def supporting_partners(request):
 @login_required
 @permission_required('scipost.can_read_partner_page', return_403=True)
 def dashboard(request):
-    '''
+    """Administration page for Partners and Prospective Partners.
+
     This page is meant as a personal page for Partners, where they will for example be able
     to read their personal data and agreements.
-    '''
+    """
     context = {}
     try:
         context['personal_agreements'] = (MembershipAgreement.objects.open_to_partner()
@@ -62,8 +63,8 @@ def dashboard(request):
         context['contact_requests_count'] = ContactRequest.objects.awaiting_processing().count()
         context['inactivate_contacts_count'] = Contact.objects.filter(user__is_active=False).count()
         context['partners'] = Partner.objects.all()
-        context['prospective_partners'] = (ProspectivePartner.objects.not_yet_partner()
-                                           .order_by('country', 'institution_name'))
+        context['prospective_partners'] = ProspectivePartner.objects.order_by(
+            'country', 'institution_name')
         context['ppevent_form'] = ProspectivePartnerEventForm()
         context['agreements'] = MembershipAgreement.objects.order_by('date_requested')
     return render(request, 'partners/dashboard.html', context)
diff --git a/scipost/constants.py b/scipost/constants.py
index 44c02c3b232db385cc9015db6a4c691585d2c322..dd7a72d42083715dfc7d0fa3db8fbca06b4c86f1 100644
--- a/scipost/constants.py
+++ b/scipost/constants.py
@@ -29,8 +29,7 @@ SCIPOST_SUBJECT_AREAS = (
         ('Phys:NE', 'Nuclear Physics - Experiment'),
         ('Phys:NT', 'Nuclear Physics - Theory'),
         ('Phys:QP', 'Quantum Physics'),
-        ('Phys:SM', 'Statistical and Soft Matter Physics'),
-        )
+        ('Phys:SM', 'Statistical and Soft Matter Physics'))
      ),
     ('Astrophysics', (
         ('Astro:GA', 'Astrophysics of Galaxies'),
@@ -38,8 +37,7 @@ SCIPOST_SUBJECT_AREAS = (
         ('Astro:EP', 'Earth and Planetary Astrophysics'),
         ('Astro:HE', 'High Energy Astrophysical Phenomena'),
         ('Astro:IM', 'Instrumentation and Methods for Astrophysics'),
-        ('Astro:SR', 'Solar and Stellar Astrophysics'),
-        )
+        ('Astro:SR', 'Solar and Stellar Astrophysics'))
      ),
     ('Mathematics', (
         ('Math:AG', 'Algebraic Geometry'),
@@ -73,8 +71,7 @@ SCIPOST_SUBJECT_AREAS = (
         ('Math:RA', 'Rings and Algebras'),
         ('Math:SP', 'Spectral Theory'),
         ('Math:ST', 'Statistics Theory'),
-        ('Math:SG', 'Symplectic Geometry'),
-        )
+        ('Math:SG', 'Symplectic Geometry'))
      ),
     ('Computer Science', (
         ('Comp:AI', 'Artificial Intelligence'),
@@ -115,9 +112,8 @@ SCIPOST_SUBJECT_AREAS = (
         ('Comp:SE', 'Software Engineering'),
         ('Comp:SD', 'Sound'),
         ('Comp:SC', 'Symbolic Computation'),
-        ('Comp:SY', 'Systems and Control'),
-        )
-     ),
+        ('Comp:SY', 'Systems and Control'))
+     )
 )
 subject_areas_raw_dict = dict(SCIPOST_SUBJECT_AREAS)
 
@@ -126,25 +122,20 @@ subject_areas_dict = {}
 for k in subject_areas_raw_dict.keys():
     subject_areas_dict.update(dict(subject_areas_raw_dict[k]))
 
-CONTRIBUTOR_NEWLY_REGISTERED = 0
-CONTRIBUTOR_NORMAL = 1
-CONTRIBUTOR_STATUS = (
-    # status determine the type of Contributor:
-    # 0: newly registered (unverified; not allowed to submit, comment or vote)
-    # 1: contributor has been vetted through
-    #
-    # Negative status denotes rejected requests or:
-    # -1: not a professional scientist (>= PhD student in known university)
-    # -2: other account already exists for this person
-    # -3: barred from SciPost (abusive behaviour)
-    # -4: disabled account (deceased)
-    (CONTRIBUTOR_NEWLY_REGISTERED, 'newly registered'),
-    (CONTRIBUTOR_NORMAL, 'normal user'),
-    (-1, 'not a professional scientist'),  # Soon to be deprecated
-    (-2, 'other account already exists'),
-    (-3, 'barred from SciPost'),
-    (-4, 'account disabled'),
-    )
+# Contributor types
+NEWLY_REGISTERED, NORMAL_CONTRIBUTOR = 'newly_registered', 'normal'
+NO_SCIENTIST, DOUBLE_ACCOUNT, OUT_OF_ACADEMIA = 'no_scientist', 'double_account', 'out_of_academia'
+BARRED, DISABLED, DECEASED = 'barred', 'disabled', 'deceased'
+CONTRIBUTOR_STATUSES = (
+    (NEWLY_REGISTERED, 'Newly registered'),
+    (NORMAL_CONTRIBUTOR, 'Normal user'),
+    (NO_SCIENTIST, 'Not a professional scientist'),
+    (DOUBLE_ACCOUNT, 'Other account already exists'),
+    (OUT_OF_ACADEMIA, 'Out of academia'),
+    (BARRED, 'Barred from SciPost'),
+    (DISABLED, 'Account disabled'),
+    (DECEASED, 'Person deceased')
+)
 
 TITLE_CHOICES = (
     ('PR', 'Prof.'),
diff --git a/scipost/decorators.py b/scipost/decorators.py
index cebaccc0221244949c78412b12bd918903266fda..fea4dc361ee19a9b8c0909cdea45f6be1b3074ff 100644
--- a/scipost/decorators.py
+++ b/scipost/decorators.py
@@ -2,13 +2,24 @@ __copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
+from django.contrib.auth.decorators import user_passes_test
+
 from .models import Contributor
 
 
 def has_contributor(user):
-    """Requires user to be related to any Contributor."""
+    """Require user to be related to any Contributor."""
     try:
         user.contributor
         return True
     except Contributor.DoesNotExist:
         return False
+
+
+def is_contributor_user():
+    """Dceorator checking if user is related to any Contributor."""
+    def test(u):
+        if u.is_authenticated():
+            return has_contributor(u)
+        return False
+    return user_passes_test(test)
diff --git a/scipost/factories.py b/scipost/factories.py
index 4c7e91d45a9430c899f093416fc7a36e69b5e57f..d058e515701c72e7a0229d2e79af31867d51fd55 100644
--- a/scipost/factories.py
+++ b/scipost/factories.py
@@ -18,7 +18,7 @@ from .constants import TITLE_CHOICES, SCIPOST_SUBJECT_AREAS
 class ContributorFactory(factory.django.DjangoModelFactory):
     title = factory.Iterator(TITLE_CHOICES, getter=lambda c: c[0])
     user = factory.SubFactory('scipost.factories.UserFactory', contributor=None)
-    status = 1  # normal user
+    status = 'normal'  # normal user
     vetted_by = factory.Iterator(Contributor.objects.all())
     personalwebpage = factory.Faker('uri')
     expertises = factory.Iterator(SCIPOST_SUBJECT_AREAS[0][1], getter=lambda c: [c[0]])
diff --git a/scipost/feeds.py b/scipost/feeds.py
index 8417bbdc3c5dce05ba8aab4441d1bcbfc97d5912..e5426b9bf44f00ca6709654d9637da739cc56dea 100644
--- a/scipost/feeds.py
+++ b/scipost/feeds.py
@@ -11,11 +11,13 @@ from django.core.urlresolvers import reverse
 from django.db.models import Q
 
 from comments.models import Comment
+from commentaries.models import Commentary
 from journals.models import Publication
 from news.models import NewsItem
 from scipost.models import subject_areas_dict
 from submissions.constants import SUBMISSION_STATUS_PUBLICLY_INVISIBLE
 from submissions.models import Submission
+from theses.models import ThesisLink
 
 
 class LatestCommentsFeedRSS(Feed):
@@ -24,7 +26,7 @@ class LatestCommentsFeedRSS(Feed):
     link = "/comments/"
 
     def items(self):
-        return Comment.objects.filter(status__gte=0).order_by('-date_submitted')[:10]
+        return Comment.objects.vetted().order_by('-date_submitted')[:10]
 
     def item_title(self, item):
         return item.comment_text[:50]
@@ -33,14 +35,14 @@ class LatestCommentsFeedRSS(Feed):
         return item.comment_text[:50]
 
     def item_link(self, item):
-        if item.commentary:
+        if isinstance(item.content_object, Commentary):
             return reverse('commentaries:commentary',
-                           kwargs={'arxiv_or_DOI_string': item.commentary.arxiv_or_DOI_string})
-        elif item.submission:
+                           kwargs={'arxiv_or_DOI_string': item.content_object.arxiv_or_DOI_string})
+        elif isinstance(item.content_object, Submission):
             return reverse('submissions:submission',
                            kwargs={'arxiv_identifier_w_vn_nr':
-                                   item.submission.arxiv_identifier_w_vn_nr})
-        elif item.thesislink:
+                                   item.content_object.arxiv_identifier_w_vn_nr})
+        elif isinstance(item.content_object, ThesisLink):
             return reverse('theses:thesis',
                            kwargs={'thesislink_id': item.thesislink.id})
         else:
diff --git a/scipost/forms.py b/scipost/forms.py
index 73a2a142d803ee568904776fb34bd6349caab0a7..7beb0185ee5b3c26ef020df792e04b290ff2effd 100644
--- a/scipost/forms.py
+++ b/scipost/forms.py
@@ -24,10 +24,11 @@ from ajax_select.fields import AutoCompleteSelectField
 from haystack.forms import ModelSearchForm as HayStackSearchForm
 
 from .behaviors import orcid_validator
-from .constants import SCIPOST_DISCIPLINES, TITLE_CHOICES, SCIPOST_FROM_ADDRESSES
+from .constants import (
+    SCIPOST_DISCIPLINES, TITLE_CHOICES, SCIPOST_FROM_ADDRESSES, NO_SCIENTIST, DOUBLE_ACCOUNT,
+    BARRED)
 from .decorators import has_contributor
-from .models import Contributor, DraftInvitation,\
-                    UnavailabilityPeriod, PrecookedEmail
+from .models import Contributor, DraftInvitation, UnavailabilityPeriod, PrecookedEmail
 
 from affiliations.models import Affiliation, Institution
 from common.forms import MonthYearWidget
@@ -39,11 +40,11 @@ from submissions.models import Report
 
 
 REGISTRATION_REFUSAL_CHOICES = (
-    (0, '-'),
-    (-1, 'not a professional scientist (>= PhD student)'),
-    (-2, 'another account already exists for this person'),
-    (-3, 'barred from SciPost (abusive behaviour)'),
-    )
+    (None, '-'),
+    (NO_SCIENTIST, 'not a professional scientist (>= PhD student)'),
+    (DOUBLE_ACCOUNT, 'another account already exists for this person'),
+    (BARRED, 'barred from SciPost (abusive behaviour)')
+)
 reg_ref_dict = dict(REGISTRATION_REFUSAL_CHOICES)
 
 
@@ -80,10 +81,10 @@ class RegistrationForm(forms.Form):
     last_name = forms.CharField(label='* Last name', max_length=100)
     email = forms.EmailField(label='* Email address')
     invitation_key = forms.CharField(max_length=40, widget=forms.HiddenInput(), required=False)
-    orcid_id = forms.CharField(label="ORCID id", max_length=20, required=False,
-                               validators=[orcid_validator],
-                               widget=forms.TextInput(
-                                    {'placeholder': 'Recommended. Get one at orcid.org'}))
+    orcid_id = forms.CharField(
+        label="ORCID id", max_length=20, required=False, validators=[orcid_validator],
+        widget=forms.TextInput({
+            'placeholder': 'Recommended. Get one at orcid.org'}))
     discipline = forms.ChoiceField(choices=SCIPOST_DISCIPLINES, label='* Main discipline')
     country_of_employment = LazyTypedChoiceField(
         choices=countries, label='* Country of employment', initial='NL',
@@ -93,12 +94,10 @@ class RegistrationForm(forms.Form):
     affiliation = forms.CharField(label='* Affiliation', max_length=300)
     address = forms.CharField(
         label='Address', max_length=1000,
-        widget=forms.TextInput({'placeholder': 'For postal correspondence'}),
-        required=False)
+        widget=forms.TextInput({'placeholder': 'For postal correspondence'}), required=False)
     personalwebpage = forms.URLField(
-        label='Personal web page',
-        widget=forms.TextInput({'placeholder': 'full URL, e.g. http://www.[yourpage].com'}),
-        required=False)
+        label='Personal web page', required=False,
+        widget=forms.TextInput({'placeholder': 'full URL, e.g. http://www.[yourpage].com'}))
     username = forms.CharField(label='* Username', max_length=100)
     password = forms.CharField(label='* Password', widget=forms.PasswordInput())
     password_verif = forms.CharField(label='* Verify password', widget=forms.PasswordInput(),
@@ -283,8 +282,9 @@ class AuthenticationForm(forms.Form):
     next = forms.CharField(widget=forms.HiddenInput(), required=False)
 
     def user_is_inactive(self):
-        """
-        Check if the User is active but only if the password is valid, to prevent any
+        """Check if the User is active only if the password is valid.
+
+        Only check  to prevent any
         possible clue (?) of the password.
         """
         username = self.cleaned_data['username']
diff --git a/scipost/management/commands/setup_contributor.py b/scipost/management/commands/setup_contributor.py
index c4798f122ef1db1b8029c14139b0a52541e95ffd..f4b98c3abb3404ebc1730601a1417ecc482dfc82 100644
--- a/scipost/management/commands/setup_contributor.py
+++ b/scipost/management/commands/setup_contributor.py
@@ -5,6 +5,7 @@ __license__ = "AGPL v3"
 from django.core.management.base import BaseCommand
 from django.contrib.auth.models import User
 
+from ...constants import NORMAL_CONTRIBUTOR
 from ...models import Contributor
 
 
@@ -16,7 +17,7 @@ class Command(BaseCommand):
 
     def create_contributor(self, username):
         user = User.objects.get(username=username)
-        contributor = Contributor(user=user, status=1, title="MR")
+        contributor = Contributor(user=user, status=NORMAL_CONTRIBUTOR, title="MR")
         contributor.vetted_by = contributor
         contributor.save()
 
diff --git a/scipost/managers.py b/scipost/managers.py
index b552f3adff613cfc6d807ce8c9e817339e7ff171..df5a60d44e538eeee8c77149556af1af3f07822e 100644
--- a/scipost/managers.py
+++ b/scipost/managers.py
@@ -6,7 +6,7 @@ from django.db import models
 from django.db.models import Q
 from django.utils import timezone
 
-from .constants import CONTRIBUTOR_NORMAL, CONTRIBUTOR_NEWLY_REGISTERED, AUTHORSHIP_CLAIM_PENDING
+from .constants import NORMAL_CONTRIBUTOR, NEWLY_REGISTERED, AUTHORSHIP_CLAIM_PENDING
 
 today = timezone.now().date()
 
@@ -23,7 +23,7 @@ class FellowManager(models.Manager):
 
 class ContributorQuerySet(models.QuerySet):
     def active(self):
-        return self.filter(user__is_active=True, status=CONTRIBUTOR_NORMAL)
+        return self.filter(user__is_active=True, status=NORMAL_CONTRIBUTOR)
 
     def available(self):
         return self.exclude(
@@ -31,10 +31,10 @@ class ContributorQuerySet(models.QuerySet):
             unavailability_periods__end__gte=today)
 
     def awaiting_validation(self):
-        return self.filter(user__is_active=False, status=CONTRIBUTOR_NEWLY_REGISTERED)
+        return self.filter(user__is_active=False, status=NEWLY_REGISTERED)
 
     def awaiting_vetting(self):
-        return self.filter(user__is_active=True, status=CONTRIBUTOR_NEWLY_REGISTERED)
+        return self.filter(user__is_active=True, status=NEWLY_REGISTERED)
 
     def fellows(self):
         return self.filter(user__groups__name='Editorial College')
diff --git a/scipost/migrations/0011_contributor_new_status.py b/scipost/migrations/0011_contributor_new_status.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ad51995a44018ac139414bc2d66744c5dfd611b
--- /dev/null
+++ b/scipost/migrations/0011_contributor_new_status.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-14 20:12
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0010_merge_20180327_2022'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='contributor',
+            name='new_status',
+            field=models.CharField(choices=[('newly_registered', 'Newly registered'), ('normal', 'Normal user'), ('no_scientist', 'Not a professional scientist'), ('double_account', 'Other account already exists'), ('out_of_academia', 'Out of academia'), ('barred', 'Barred from SciPost'), ('disabled', 'Account disabled'), ('deceased', 'Person deceased')], default='newly_registered', max_length=16),
+        ),
+    ]
diff --git a/scipost/migrations/0012_auto_20180414_2212.py b/scipost/migrations/0012_auto_20180414_2212.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3faed8fd33b8ffbd9a04432e42a627949b3b9ab
--- /dev/null
+++ b/scipost/migrations/0012_auto_20180414_2212.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-14 20:12
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+def update_contributor_status_field(apps, schema_editor):
+    Contributor = apps.get_model('scipost', 'Contributor')
+
+    Contributor.objects.filter(status=-4).update(new_status='disabled')
+    Contributor.objects.filter(status=-3).update(new_status='barred')
+    Contributor.objects.filter(status=-2).update(new_status='double_account')
+    Contributor.objects.filter(status=-1).update(new_status='no_scientist')
+    Contributor.objects.filter(status=0).update(new_status='newly_registered')
+    Contributor.objects.filter(status=1).update(new_status='normal')
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0011_contributor_new_status'),
+    ]
+
+    operations = [
+        migrations.RunPython(update_contributor_status_field)
+    ]
diff --git a/scipost/migrations/0013_remove_contributor_status.py b/scipost/migrations/0013_remove_contributor_status.py
new file mode 100644
index 0000000000000000000000000000000000000000..7dfb7cc212142c45870d0fbea11d73a5f972f7cc
--- /dev/null
+++ b/scipost/migrations/0013_remove_contributor_status.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-14 20:18
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0012_auto_20180414_2212'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='contributor',
+            name='status',
+        ),
+    ]
diff --git a/scipost/migrations/0014_auto_20180414_2218.py b/scipost/migrations/0014_auto_20180414_2218.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2782391c11e94bc712aa0c98de6c7a3ee192a3c
--- /dev/null
+++ b/scipost/migrations/0014_auto_20180414_2218.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2018-04-14 20:18
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0013_remove_contributor_status'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='contributor',
+            old_name='new_status',
+            new_name='status',
+        ),
+    ]
diff --git a/scipost/models.py b/scipost/models.py
index 9f358b52c9bac2ee022a4ce26f65cb76523c76d6..d5bc608c42a3a3d4eca6b37aab37128958c259d9 100644
--- a/scipost/models.py
+++ b/scipost/models.py
@@ -15,40 +15,39 @@ from django.db import models
 from django.utils import timezone
 
 from .behaviors import TimeStampedModel, orcid_validator
-from .constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS,\
-                       subject_areas_dict, CONTRIBUTOR_STATUS, TITLE_CHOICES,\
-                       INVITATION_STYLE, INVITATION_TYPE,\
-                       INVITATION_CONTRIBUTOR, INVITATION_FORMAL,\
-                       AUTHORSHIP_CLAIM_PENDING, AUTHORSHIP_CLAIM_STATUS,\
-                       CONTRIBUTOR_NEWLY_REGISTERED
+from .constants import (
+    SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS, subject_areas_dict, DISABLED,
+    TITLE_CHOICES, INVITATION_STYLE, INVITATION_TYPE, INVITATION_CONTRIBUTOR, INVITATION_FORMAL,
+    AUTHORSHIP_CLAIM_PENDING, AUTHORSHIP_CLAIM_STATUS, CONTRIBUTOR_STATUSES, NEWLY_REGISTERED)
 from .fields import ChoiceArrayField
-from .managers import FellowManager, ContributorQuerySet,\
-                      UnavailabilityPeriodManager, AuthorshipClaimQuerySet
+from .managers import (
+    FellowManager, ContributorQuerySet, UnavailabilityPeriodManager, AuthorshipClaimQuerySet)
 
 today = timezone.now().date()
 
 
 def get_sentinel_user():
-    '''
-    Temporary fix: eventually the 'to-be-removed-Contributor' should be
-    status: "deactivated" and anonymized.
+    """Temporary fix to be able to delete Contributor instances.
+
+    Eventually the 'to-be-removed-Contributor' should be status: "deactivated" and anonymized.
     Fallback user for models relying on Contributor that is being deleted.
-    '''
+    """
     user, __ = get_user_model().objects.get_or_create(username='deleted')
-    return Contributor.objects.get_or_create(status=-4, user=user)[0]
+    return Contributor.objects.get_or_create(status=DISABLED, user=user)[0]
 
 
 class Contributor(models.Model):
-    """
+    """A Contributor is an academic extention of the User model.
+
     All *science* users of SciPost are Contributors.
     username, password, email, first_name and last_name are inherited from User.
     """
+
     user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, unique=True)
     invitation_key = models.CharField(max_length=40, blank=True)
     activation_key = models.CharField(max_length=40, blank=True)
     key_expires = models.DateTimeField(default=timezone.now)
-    status = models.SmallIntegerField(default=CONTRIBUTOR_NEWLY_REGISTERED,
-                                      choices=CONTRIBUTOR_STATUS)
+    status = models.CharField(max_length=16, choices=CONTRIBUTOR_STATUSES, default=NEWLY_REGISTERED)
     title = models.CharField(max_length=4, choices=TITLE_CHOICES)
     discipline = models.CharField(max_length=20, choices=SCIPOST_DISCIPLINES,
                                   default='physics', verbose_name='Main discipline')
@@ -57,16 +56,12 @@ class Contributor(models.Model):
         blank=True, null=True)
     orcid_id = models.CharField(max_length=20, verbose_name="ORCID id",
                                 blank=True, validators=[orcid_validator])
-    address = models.CharField(max_length=1000, verbose_name="address",
-                               blank=True)
-    personalwebpage = models.URLField(verbose_name='personal web page',
-                                      blank=True)
+    address = models.CharField(max_length=1000, verbose_name="address", blank=True)
+    personalwebpage = models.URLField(verbose_name='personal web page', blank=True)
     vetted_by = models.ForeignKey('self', on_delete=models.SET(get_sentinel_user),
-                                  related_name="contrib_vetted_by",
-                                  blank=True, null=True)
+                                  related_name="contrib_vetted_by", blank=True, null=True)
     accepts_SciPost_emails = models.BooleanField(
-        default=True,
-        verbose_name="I accept to receive SciPost emails")
+        default=True, verbose_name="I accept to receive SciPost emails")
 
     objects = ContributorQuerySet.as_manager()
 
@@ -74,48 +69,50 @@ class Contributor(models.Model):
         return '%s, %s' % (self.user.last_name, self.user.first_name)
 
     def save(self, *args, **kwargs):
+        """Generate new activitation key if not set."""
         if not self.activation_key:
             self.generate_key()
         return super().save(*args, **kwargs)
 
     def get_absolute_url(self):
+        """Return public information page url."""
         return reverse('scipost:contributor_info', args=(self.id,))
 
-    @property
-    def get_formal_display(self):
-        return '%s %s %s' % (self.get_title_display(), self.user.first_name, self.user.last_name)
-
     @property
     def is_currently_available(self):
+        """Check if Contributor is currently not marked as unavailable."""
         return not self.unavailability_periods.today().exists()
 
     def is_EdCol_Admin(self):
+        """Check if Contributor is an Editorial Administrator."""
         return (self.user.groups.filter(name='Editorial Administrators').exists()
                 or self.user.is_superuser)
 
     def is_SP_Admin(self):
+        """Check if Contributor is a SciPost Administrator."""
         return (self.user.groups.filter(name='SciPost Administrators').exists()
                 or self.user.is_superuser)
 
     def is_MEC(self):
+        """Check if Contributor is a member of the Editorial College."""
         return self.fellowships.active().exists() or self.user.is_superuser
 
     def is_VE(self):
+        """Check if Contributor is a Vetting Editor."""
         return (self.user.groups.filter(name='Vetting Editors').exists()
                 or self.user.is_superuser)
 
     def generate_key(self, feed=''):
-        """
-        Generate and save a new activation_key for the contributor, given a certain feed.
-        """
+        """Generate a new activation_key for the contributor, given a certain feed."""
         for i in range(5):
             feed += random.choice(string.ascii_letters)
         feed = feed.encode('utf8')
         salt = self.user.username.encode('utf8')
-        self.activation_key = hashlib.sha1(salt+salt).hexdigest()
+        self.activation_key = hashlib.sha1(salt + salt).hexdigest()
         self.key_expires = datetime.datetime.now() + datetime.timedelta(days=2)
 
     def expertises_as_string(self):
+        """Return joined expertises."""
         if self.expertises:
             return ', '.join([subject_areas_dict[exp].lower() for exp in self.expertises])
         return ''
diff --git a/scipost/static/scipost/images/FJN-logo-long.png b/scipost/static/scipost/images/FJN-logo-long.png
new file mode 100755
index 0000000000000000000000000000000000000000..93860c5a2f5c1644e9c4858c398949ec7f0d6390
Binary files /dev/null and b/scipost/static/scipost/images/FJN-logo-long.png differ
diff --git a/scipost/static/scipost/info/AnnualReports/AnnualReport_2015.pdf b/scipost/static/scipost/info/AnnualReports/AnnualReport_2015.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..6c6473508a5e182cf496f627afd2e966ecbc0b5b
Binary files /dev/null and b/scipost/static/scipost/info/AnnualReports/AnnualReport_2015.pdf differ
diff --git a/scipost/static/scipost/info/AnnualReports/AnnualReport_2016.pdf b/scipost/static/scipost/info/AnnualReports/AnnualReport_2016.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..6bd811577587c7a1d60dcf8827fb20ba29a5b824
Binary files /dev/null and b/scipost/static/scipost/info/AnnualReports/AnnualReport_2016.pdf differ
diff --git a/scipost/static/scipost/info/AnnualReports/AnnualReport_2017.pdf b/scipost/static/scipost/info/AnnualReports/AnnualReport_2017.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..43863e00252e7fb34366a408d0836ec17821fa3d
Binary files /dev/null and b/scipost/static/scipost/info/AnnualReports/AnnualReport_2017.pdf differ
diff --git a/scipost/templates/partials/scipost/personal_page/account.html b/scipost/templates/partials/scipost/personal_page/account.html
index bfda86979026a266428a272d69dc8e4e5b2b9d1e..43e350ba7295fd8f3707fe43756b793d40a18520 100644
--- a/scipost/templates/partials/scipost/personal_page/account.html
+++ b/scipost/templates/partials/scipost/personal_page/account.html
@@ -102,6 +102,15 @@
 
                     {% if fellowship.guest %}
                         (Guest Fellowship)
+                        <br>
+                        Your Proceedings:
+                        <ul>
+                            {% for proc in fellowship.proceedings.all %}
+                                <li>{{ proc }}</li>
+                            {% empty %}
+                                <li><em>No proceedings assigned yet.</em></li>
+                            {% endfor %}
+                        </ul>
                     {% else %}
                         (Regular Fellowship)
                     {% endif %}
diff --git a/scipost/templates/scipost/bare_base.html b/scipost/templates/scipost/bare_base.html
index fbfb7b288ed8f36a1e814836c0eb22981202e85e..5efb4b3aed589d63858c7c6cde5cadd1d0a8d2bf 100644
--- a/scipost/templates/scipost/bare_base.html
+++ b/scipost/templates/scipost/bare_base.html
@@ -9,7 +9,7 @@
     <link href="https://fonts.googleapis.com/css?family=Merriweather+Sans:300,400,700" rel="stylesheet">
     <link rel="stylesheet" type="text/css" href="{% static 'scipost/SciPost.css' %}" />
     <link rel="stylesheet" type="text/css" href="{% static 'fa/css/font-awesome.min.css' %}" />
-    <script async src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
+    <script async src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
     <script async src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
 
     {% render_bundle 'main' 'css' %}
diff --git a/scipost/templates/scipost/contributor_info.html b/scipost/templates/scipost/contributor_info.html
index 26423a9502582d3579c1ea106e3e1e9752c701fa..d65751ed7db2636235ff7754b3725448eed99fb8 100644
--- a/scipost/templates/scipost/contributor_info.html
+++ b/scipost/templates/scipost/contributor_info.html
@@ -4,7 +4,7 @@
 
 {% block content %}
 
-<h1 class="highlight mb-4">Contributor info: {{ contributor.get_formal_display }}</h1>
+<h1 class="highlight mb-4">Contributor info: {{ contributor.get_title_display }} {{ contributor.user.first_name }} {{ contributor.user.last_name }}</h1>
 
 {% include "scipost/_public_info_as_table.html" with contributor=contributor %}
 
diff --git a/scipost/templates/scipost/foundation.html b/scipost/templates/scipost/foundation.html
index 75430efccb88624bb861a053398ca155faa504e5..d541dee897dfa5f9fb7b39264c77ca27a7186349 100644
--- a/scipost/templates/scipost/foundation.html
+++ b/scipost/templates/scipost/foundation.html
@@ -71,16 +71,6 @@
                 </div>
             </div>
 
-            <div class="card bg-white border-0">
-                <div class="card-body">
-                    <h2 class="highlight">Registration</h2>
-                  	<p class="px-2">
-                        Dutch Chamber of Commerce nr 65280083.</br>
-                  	    RSIN 856049487.<br>
-                  	    <a href="{% static 'scipost/info/uittreksel_Stichting_SciPost.pdf' %}">Registration extract</a>.
-                     </p>
-                </div>
-            </div>
         </div>
     </div>
 </div>
@@ -88,23 +78,33 @@
 <div class="row">
     <div class="col-12">
         <div class="card-deck">
+<!--
             <div class="card bg-white border-0">
                 <div class="card-body">
-                    <h2 class="highlight">Registration</h2>
+                    <h2 class="highlight">Yearly Reports</h2>
+                    <p class="px-2">2016 (to be published)</p>
                 </div>
             </div>
-
+-->
             <div class="card bg-white border-0">
                 <div class="card-body">
-                    <h2 class="highlight">Yearly Reports</h2>
-                    <p class="px-2">2016 (to be published)</p>
+                    <h2 class="highlight">Registration</h2>
+                  	<p class="px-2">
+                        Dutch Chamber of Commerce nr 65280083.</br>
+                  	    RSIN 856049487.<br>
+                  	    <a href="{% static 'scipost/info/uittreksel_Stichting_SciPost.pdf' %}">Registration extract</a>.
+                     </p>
                 </div>
             </div>
 
             <div class="card bg-white border-0">
                 <div class="card-body">
                     <h2 class="highlight">Financial Reports</h2>
-                    <p class="px-2">2016-7 (to be published)</p>
+		    <ul>
+                      <li><a href="{% static 'scipost/info/AnnualReports/AnnualReport_2015.pdf' %}">Annual Report 2015</a></li>
+                    <li><a href="{% static 'scipost/info/AnnualReports/AnnualReport_2016.pdf' %}">Annual Report 2016</a></li>
+                    <li><a href="{% static 'scipost/info/AnnualReports/AnnualReport_2017.pdf' %}">Annual Report 2017</a></li>
+		    </ul>
                 </div>
             </div>
         </div>
diff --git a/scipost/templates/scipost/index.html b/scipost/templates/scipost/index.html
index 5546719426f347d435abd1155666200f886a4429..58b56563081658effeb20a2c355c1705e1637b41 100644
--- a/scipost/templates/scipost/index.html
+++ b/scipost/templates/scipost/index.html
@@ -195,6 +195,7 @@
                 <a href="//www.doaj.org" target="_blank"><img src="{% static 'scipost/images/doaj_logo_200.jpg' %}" width="90" alt="DOAJ logo"></a>
                 <a href="//www.clockss.org" target="_blank"><img src="{% static 'scipost/images/clockss_original_logo_boxed_ai-cropped-90.png' %}" width="80" alt="Clockss logo"></a>
                 <a href="//i4oc.org/" target="_blank"><img width="100" src="{% static 'scipost/images/I4OC.png' %}"></a>
+		<a href="//freejournals.org" target="_blank"><img width="100" src="{% static 'scipost/images/FJN-logo-long.png' %}"></a>
             </div>
 	    </div>
 	    <div class="row">
diff --git a/scipost/views.py b/scipost/views.py
index 9c9ba8c786e6f0739759f8682df5cd4c3db2a51f..915df08f3fa3e0bfdc34fbef5b55fdda1e969eb5 100644
--- a/scipost/views.py
+++ b/scipost/views.py
@@ -9,7 +9,7 @@ from django.shortcuts import get_object_or_404, render
 from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth import login, logout, update_session_auth_hash
-from django.contrib.auth.decorators import login_required, user_passes_test
+from django.contrib.auth.decorators import login_required
 from django.contrib.auth.models import Group
 from django.contrib.auth.views import password_reset, password_reset_confirm
 from django.core import mail
@@ -29,16 +29,16 @@ from django.views.static import serve
 from guardian.decorators import permission_required
 from haystack.generic_views import SearchView
 
-from .constants import SCIPOST_SUBJECT_AREAS, subject_areas_raw_dict, SciPost_from_addresses_dict,\
-                       CONTRIBUTOR_NORMAL
-from .decorators import has_contributor
-from .models import Contributor, UnavailabilityPeriod,\
-                    AuthorshipClaim, EditorialCollege, EditorialCollegeFellowship
-from .forms import AuthenticationForm, UnavailabilityPeriodForm,\
-                   RegistrationForm, AuthorshipClaimForm,\
-                   SearchForm, VetRegistrationForm, reg_ref_dict,\
-                   UpdatePersonalDataForm, UpdateUserDataForm, PasswordChangeForm,\
-                   EmailGroupMembersForm, EmailParticularForm, SendPrecookedEmailForm
+from .constants import (
+    SCIPOST_SUBJECT_AREAS, subject_areas_raw_dict, SciPost_from_addresses_dict, NORMAL_CONTRIBUTOR)
+from .decorators import has_contributor, is_contributor_user
+from .models import (
+    Contributor, UnavailabilityPeriod, AuthorshipClaim, EditorialCollege,
+    EditorialCollegeFellowship)
+from .forms import (
+    AuthenticationForm, UnavailabilityPeriodForm, RegistrationForm, AuthorshipClaimForm,
+    SearchForm, VetRegistrationForm, reg_ref_dict, UpdatePersonalDataForm, UpdateUserDataForm,
+    PasswordChangeForm, EmailGroupMembersForm, EmailParticularForm, SendPrecookedEmailForm)
 from .utils import Utils, EMAIL_FOOTER, SCIPOST_SUMMARY_FOOTER, SCIPOST_SUMMARY_FOOTER_HTML
 
 from affiliations.forms import AffiliationsFormset
@@ -49,8 +49,7 @@ from invitations.constants import STATUS_REGISTERED
 from invitations.models import RegistrationInvitation
 from journals.models import Publication, Journal, PublicationAuthorsTable
 from news.models import NewsItem
-from submissions.models import Submission, RefereeInvitation,\
-                               Report, EICRecommendation
+from submissions.models import Submission, RefereeInvitation, Report, EICRecommendation
 from partners.models import MembershipAgreement
 from theses.models import ThesisLink
 
@@ -60,18 +59,18 @@ from theses.models import ThesisLink
 ##############
 
 def is_registered(user):
-    """
-    This method checks if user is activated assuming an validated user
-    has at least one permission group (`Registered Contributor` or `Partner Accounts`).
-    """
+    """Check if user is a validated user; has at least one permission group."""
     return user.groups.exists()
 
 
 class SearchView(SearchView):
+    """Search CBV inherited from Haystack."""
+
     template_name = 'search/search.html'
     form_class = SearchForm
 
     def get_context_data(self, *args, **kwargs):
+        """Update context with some additional information."""
         ctx = super().get_context_data(*args, **kwargs)
         ctx['search_query'] = self.request.GET.get('q')
         ctx['results_count'] = kwargs['object_list'].count()
@@ -83,7 +82,7 @@ class SearchView(SearchView):
 #############
 
 def index(request):
-    '''Main page.'''
+    """Homepage view of SciPost."""
     context = {
         'latest_newsitem': NewsItem.objects.filter(on_homepage=True).order_by('-date').first(),
         'submissions': Submission.objects.public().order_by('-submission_date')[:3],
@@ -96,7 +95,8 @@ def index(request):
 
 
 def protected_serve(request, path, show_indexes=False):
-    """
+    """Serve media files from outside the public MEDIA_ROOT folder.
+
     Serve files that are saved outside the default MEDIA_ROOT folder for superusers only!
     This will be usefull eg. in the admin pages.
     """
@@ -112,6 +112,7 @@ def protected_serve(request, path, show_indexes=False):
 ###############
 
 def feeds(request):
+    """Information page for RSS and Atom feeds."""
     context = {'subject_areas_physics': SCIPOST_SUBJECT_AREAS[0][1]}
     return render(request, 'scipost/feeds.html', context)
 
@@ -121,7 +122,8 @@ def feeds(request):
 ################
 
 def register(request):
-    """
+    """Contributor registration form page.
+
     This public registration view shows and processes the form
     that will create new user account requests. After registration
     the Contributor will need to activate its account via the mail
@@ -155,7 +157,8 @@ def register(request):
 
 
 def invitation(request, key):
-    """
+    """Registration Invitation reception page.
+
     If a scientist has recieved an invitation (RegistrationInvitation)
     he/she will finish it's invitation via still view which will prefill
     the default registration form.
@@ -244,9 +247,8 @@ def unsubscribe(request, contributor_id, key):
 
 @permission_required('scipost.can_vet_registration_requests', return_403=True)
 def vet_registration_requests(request):
-    contributors_to_vet = (Contributor.objects
-                           .awaiting_vetting()
-                           .order_by('key_expires'))
+    """List of new Registration requests to vet."""
+    contributors_to_vet = Contributor.objects.awaiting_vetting().order_by('key_expires')
     form = VetRegistrationForm()
     context = {'contributors_to_vet': contributors_to_vet, 'form': form}
     return render(request, 'scipost/vet_registration_requests.html', context)
@@ -254,12 +256,12 @@ def vet_registration_requests(request):
 
 @permission_required('scipost.can_vet_registration_requests', return_403=True)
 def vet_registration_request_ack(request, contributor_id):
-    # process the form
+    """Form view to vet new Registration requests."""
     form = VetRegistrationForm(request.POST or None)
     contributor = Contributor.objects.get(pk=contributor_id)
     if form.is_valid():
         if form.promote_to_registered_contributor():
-            contributor.status = 1
+            contributor.status = NORMAL_CONTRIBUTOR
             contributor.vetted_by = request.user.contributor
             contributor.save()
             group = Group.objects.get(name='Registered Contributors')
@@ -274,11 +276,10 @@ def vet_registration_request_ack(request, contributor_id):
             except RefereeInvitation.DoesNotExist:
                 pending_ref_inv_exists = False
 
-            email_text = ('Dear ' + contributor.get_title_display() + ' '
-                          + contributor.user.last_name +
-                          ', \n\nYour registration to the SciPost publication portal '
-                          'has been accepted. '
-                          'You can now login at https://scipost.org and contribute. \n\n')
+            email_text = (
+                'Dear ' + contributor.get_title_display() + ' ' + contributor.user.last_name +
+                ', \n\nYour registration to the SciPost publication portal has been accepted. '
+                'You can now login at https://scipost.org and contribute. \n\n')
             if pending_ref_inv_exists:
                 email_text += (
                     'Note that you have pending refereeing invitations; please navigate to '
@@ -292,18 +293,16 @@ def vet_registration_request_ack(request, contributor_id):
                                         reply_to=['registration@scipost.org'])
             emailmessage.send(fail_silently=False)
         else:
-            ref_reason = int(form.cleaned_data['refusal_reason'])
-            email_text = ('Dear ' + contributor.get_title_display() + ' '
-                          + contributor.user.last_name +
-                          ', \n\nYour registration to the SciPost publication portal '
-                          'has been turned down, the reason being: '
-                          + reg_ref_dict[ref_reason] + '. You can however still view '
-                          'all SciPost contents, just not submit papers, '
-                          'comments or votes. We nonetheless thank you for your interest.'
-                          '\n\nThe SciPost Team.')
+            ref_reason = form.cleaned_data['refusal_reason']
+            email_text = (
+                'Dear ' + contributor.get_title_display() + ' ' + contributor.user.last_name +
+                ', \n\nYour registration to the SciPost publication portal has been turned down,'
+                ' the reason being: ' + reg_ref_dict[ref_reason] + '. You can however still view '
+                'all SciPost contents, just not submit papers, comments or votes. We nonetheless '
+                'thank you for your interest.\n\nThe SciPost Team.')
             if form.cleaned_data['email_response_field']:
-                email_text += ('\n\nFurther explanations: '
-                               + form.cleaned_data['email_response_field'])
+                email_text += (
+                    '\n\nFurther explanations: ' + form.cleaned_data['email_response_field'])
             emailmessage = EmailMessage('SciPost registration: unsuccessful',
                                         email_text,
                                         'SciPost registration <registration@scipost.org>',
@@ -337,9 +336,7 @@ def registration_requests(request):
 @require_POST
 @permission_required('scipost.can_resend_registration_requests', return_403=True)
 def registration_requests_reset(request, contributor_id):
-    '''
-    Reset specific activation_key for Contributor and resend activation mail.
-    '''
+    """Reset specific activation_key for Contributor and resend activation mail."""
     contributor = get_object_or_404(Contributor.objects.awaiting_validation(), id=contributor_id)
     contributor.generate_key()
     contributor.save()
@@ -351,15 +348,7 @@ def registration_requests_reset(request, contributor_id):
 
 
 def login_view(request):
-    """
-    This view shows and processes a user's login session.
-
-    The function based method login() is deprecated from
-    Django 1.11 and replaced by Class Based Views.
-
-    See:
-    https://docs.djangoproject.com/en/1.11/releases/1.11/#django-contrib-auth
-    """
+    """Login form page."""
     form = AuthenticationForm(request.POST or None, initial=request.GET)
     if form.is_valid():
         user = form.authenticate()
@@ -381,13 +370,7 @@ def login_view(request):
 
 
 def logout_view(request):
-    """
-    The function based method logout() is deprecated from
-    Django 1.11 and replaced by Class Based Views.
-
-    See:
-    https://docs.djangoproject.com/en/1.11/releases/1.11/#django-contrib-auth
-    """
+    """Logout form page."""
     logout(request)
     messages.success(request, ('<h3>Keep contributing!</h3>'
                                'You are now logged out of SciPost.'))
@@ -395,11 +378,9 @@ def logout_view(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def mark_unavailable_period(request):
-    '''
-    Mark period unavailable for Contributor using this view.
-    '''
+    """Form view to mark period unavailable for Contributor."""
     unav_form = UnavailabilityPeriodForm(request.POST or None)
     if unav_form.is_valid():
         unav = unav_form.save(commit=False)
@@ -415,11 +396,9 @@ def mark_unavailable_period(request):
 
 @require_POST
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def delete_unavailable_period(request, period_id):
-    '''
-    Delete period unavailable registered.
-    '''
+    """Delete period unavailable registered."""
     unav = get_object_or_404(UnavailabilityPeriod,
                              contributor=request.user.contributor, id=int(period_id))
     unav.delete()
@@ -428,11 +407,9 @@ def delete_unavailable_period(request, period_id):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_editorial_account(request):
-    """
-    The Personal Page tab: Account
-    """
+    """Personal Page tab: Account."""
     contributor = request.user.contributor
     context = {
         'contributor': contributor,
@@ -442,11 +419,9 @@ def _personal_page_editorial_account(request):
     return render(request, 'partials/scipost/personal_page/account.html', context)
 
 
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_editorial_actions(request):
-    """
-    The Personal Page tab: Editorial Actions
-    """
+    """Personal Page tab: Editorial Actions."""
     permission = request.user.groups.filter(name__in=[
         'Ambassadors',
         'Advisory Board',
@@ -491,11 +466,9 @@ def _personal_page_editorial_actions(request):
 
 
 @permission_required('scipost.can_referee', return_403=True)
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_refereeing(request):
-    """
-    The Personal Page tab: Refereeing
-    """
+    """Personal Page tab: Refereeing."""
     context = {
         'contributor': request.user.contributor
     }
@@ -503,11 +476,9 @@ def _personal_page_refereeing(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_publications(request):
-    """
-    The Personal Page tab: Publications
-    """
+    """Personal Page tab: Publications."""
     contributor = request.user.contributor
     context = {
         'contributor': contributor,
@@ -522,11 +493,9 @@ def _personal_page_publications(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_submissions(request):
-    """
-    The Personal Page tab: Submissions
-    """
+    """Personal Page tab: Submissions."""
     contributor = request.user.contributor
     context = {'contributor': contributor}
 
@@ -541,11 +510,9 @@ def _personal_page_submissions(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_commentaries(request):
-    """
-    The Personal Page tab: Commentaries
-    """
+    """Personal Page tab: Commentaries."""
     contributor = request.user.contributor
     context = {'contributor': contributor}
 
@@ -559,11 +526,9 @@ def _personal_page_commentaries(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_theses(request):
-    """
-    The Personal Page tab: Theses
-    """
+    """Personal Page tab: Theses."""
     contributor = request.user.contributor
     context = {'contributor': contributor}
 
@@ -577,11 +542,9 @@ def _personal_page_theses(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_comments(request):
-    """
-    The Personal Page tab: Comments
-    """
+    """Personal Page tab: Comments."""
     contributor = request.user.contributor
     context = {
         'contributor': contributor,
@@ -592,11 +555,9 @@ def _personal_page_comments(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def _personal_page_author_replies(request):
-    """
-    The Personal Page tab: Author Replies
-    """
+    """Personal Page tab: Author Replies."""
     contributor = request.user.contributor
     context = {
         'contributor': contributor,
@@ -608,9 +569,7 @@ def _personal_page_author_replies(request):
 
 @login_required
 def personal_page(request, tab='account'):
-    """
-    The Personal Page is the main view for accessing user functions.
-    """
+    """Personal Page is the main view for accessing user functions."""
     if request.is_ajax():
         if tab == 'account':
             return _personal_page_editorial_account(request)
@@ -640,7 +599,7 @@ def personal_page(request, tab='account'):
 
     try:
         contributor = Contributor.objects.select_related('user').get(user=request.user)
-        context['needs_validation'] = contributor.status != CONTRIBUTOR_NORMAL
+        context['needs_validation'] = contributor.status != NORMAL_CONTRIBUTOR
     except Contributor.DoesNotExist:
         contributor = None
 
@@ -659,6 +618,7 @@ def personal_page(request, tab='account'):
 
 @login_required
 def change_password(request):
+    """Change password form view."""
     form = PasswordChangeForm(request.POST or None, current_user=request.user)
     if form.is_valid():
         form.save_new_password()
@@ -729,7 +689,7 @@ def update_personal_data(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def claim_authorships(request):
     """
     The system auto-detects potential authorships (of submissions,
@@ -778,7 +738,7 @@ def claim_authorships(request):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def claim_pub_authorship(request, publication_id, claim):
     if request.method == 'POST':
         contributor = Contributor.objects.get(user=request.user)
@@ -794,7 +754,7 @@ def claim_pub_authorship(request, publication_id, claim):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def claim_sub_authorship(request, submission_id, claim):
     if request.method == 'POST':
         contributor = Contributor.objects.get(user=request.user)
@@ -810,7 +770,7 @@ def claim_sub_authorship(request, submission_id, claim):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def claim_com_authorship(request, commentary_id, claim):
     if request.method == 'POST':
         contributor = Contributor.objects.get(user=request.user)
@@ -826,7 +786,7 @@ def claim_com_authorship(request, commentary_id, claim):
 
 
 @login_required
-@user_passes_test(has_contributor)
+@is_contributor_user()
 def claim_thesis_authorship(request, thesis_id, claim):
     if request.method == 'POST':
         contributor = Contributor.objects.get(user=request.user)
@@ -908,10 +868,10 @@ def contributor_info(request, contributor_id):
     contributor_submissions = Submission.objects.public_unlisted().filter(authors=contributor)
     contributor_commentaries = Commentary.objects.filter(authors=contributor)
     contributor_theses = ThesisLink.objects.vetted().filter(author_as_cont=contributor)
-    contributor_comments = (Comment.objects.vetted()
+    contributor_comments = (Comment.objects.vetted().publicly_visible()
                             .filter(author=contributor, is_author_reply=False)
                             .order_by('-date_submitted'))
-    contributor_authorreplies = (Comment.objects.vetted()
+    contributor_authorreplies = (Comment.objects.vetted().publicly_visible()
                                  .filter(author=contributor, is_author_reply=True)
                                  .order_by('-date_submitted'))
     context = {'contributor': contributor,
diff --git a/submissions/forms.py b/submissions/forms.py
index c07f76b1fe3bd5a4ad07c51f5b3455930140ee98..7aa45b91c4a90757b431f9743a3f1e89715d7c64 100644
--- a/submissions/forms.py
+++ b/submissions/forms.py
@@ -24,7 +24,7 @@ from .models import (
 from common.helpers import get_new_secrets_key
 from colleges.models import Fellowship
 from invitations.models import RegistrationInvitation
-from journals.constants import SCIPOST_JOURNAL_PHYSICS_PROC
+from journals.constants import SCIPOST_JOURNAL_PHYSICS_PROC, SCIPOST_JOURNAL_PHYSICS
 from scipost.constants import SCIPOST_SUBJECT_AREAS, INVITATION_REFEREEING
 from scipost.services import ArxivCaller
 from scipost.models import Contributor
@@ -290,6 +290,7 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm):
             del self.fields['proceedings']
 
         # Update placeholder for the other fields
+        self.fields['submission_type'].required = False
         self.fields['arxiv_link'].widget.attrs.update({
             'placeholder': 'ex.:  arxiv.org/abs/1234.56789v1'})
         self.fields['abstract'].widget.attrs.update({'cols': 100})
@@ -322,9 +323,8 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm):
         return cleaned_data
 
     def clean_author_list(self):
-        """
-        Important check!
-
+        """Check if author list matches the Contributor submitting.
+    
         The submitting user must be an author of the submission.
         Also possibly may be extended to check permissions and give ultimate submission
         power to certain user groups.
@@ -336,12 +336,20 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm):
             raise forms.ValidationError(error_message, code='not_an_author')
         return author_list
 
+    def clean_submission_type(self):
+        """Validate Submission type.
+
+        The SciPost Physics journal requires a Submission type to be specified.
+        """
+        submission_type = self.cleaned_data['submission_type']
+        journal = self.cleaned_data['submitted_to_journal']
+        if journal == SCIPOST_JOURNAL_PHYSICS and not submission_type:
+            self.add_error('submission_type', 'Please specify the submission type.')
+        return submission_type
+
     @transaction.atomic
     def copy_and_save_data_from_resubmission(self, submission):
-        """
-        Fill given Submission with data coming from last_submission in the SubmissionChecks
-        blueprint.
-        """
+        """Fill given Submission with data coming from last_submission."""
         if not self.last_submission:
             raise Submission.DoesNotExist
 
diff --git a/submissions/models.py b/submissions/models.py
index 4f704ce629d484af7b342e8bdde8c4cd4b915d0c..0b4b43423c3132d5183ad1addb73fa6ca3fabed4 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -3,6 +3,7 @@ __license__ = "AGPL v3"
 
 
 import datetime
+import feedparser
 
 from django.contrib.postgres.fields import JSONField
 from django.contrib.contenttypes.fields import GenericRelation
@@ -74,6 +75,8 @@ class Submission(models.Model):
 
     fellows = models.ManyToManyField('colleges.Fellowship', blank=True,
                                      related_name='pool')
+    # visible_pool = models.BooleanField(default=True)
+    # visible_public = models.BooleanField(default=False)
     subject_area = models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS,
                                     verbose_name='Primary subject area', default='Phys:QP')
     submission_type = models.CharField(max_length=10, choices=SUBMISSION_TYPE)
@@ -277,6 +280,32 @@ class Submission(models.Model):
         )
         event.save()
 
+    """
+    Identify coauthorships from arXiv, using author surname matching.
+    """
+    def flag_coauthorships_arxiv(self, fellows):
+        coauthorships = {}
+        if self.metadata and 'entries' in self.metadata:
+            author_last_names = []
+            for author in self.metadata['entries'][0]['authors']:
+                # Gather author data to do conflict-of-interest queries with
+                author_last_names.append(author['name'].split()[-1])
+            authors_last_names_str = '+OR+'.join(author_last_names)
+
+            for fellow in fellows:
+                # For each fellow found, so a query with the authors to check for conflicts
+                search_query = 'au:({fellow}+AND+({authors}))'.format(
+                    fellow=fellow.contributor.user.last_name,
+                    authors=authors_last_names_str)
+                queryurl = 'https://export.arxiv.org/api/query?search_query={sq}'.format(
+                    sq=search_query)
+                queryurl += '&sortBy=submittedDate&sortOrder=descending&max_results=5'
+                queryurl = queryurl.replace(' ', '+')  # Fallback for some last names with spaces
+                queryresults = feedparser.parse(queryurl)
+                if queryresults.entries:
+                    coauthorships[fellow.contributor.user.last_name] = queryresults.entries
+        return coauthorships
+
 
 class SubmissionEvent(SubmissionRelatedObjectMixin, TimeStampedModel):
     """Private message directly related to a Submission.
diff --git a/submissions/templates/partials/submissions/admin/editorial_assignment_failed.html b/submissions/templates/partials/submissions/admin/editorial_assignment_failed.html
new file mode 100644
index 0000000000000000000000000000000000000000..09bd150d83dac7dbc9371018115fe3498d284cc6
--- /dev/null
+++ b/submissions/templates/partials/submissions/admin/editorial_assignment_failed.html
@@ -0,0 +1,13 @@
+<h1 class="highlight">Assignment has failed for Submission</h1>
+<h3>Submission details</h3>
+{% include 'partials/submissions/submission_summary.html' with submission=object %}
+
+<br>
+<h3>Current EIC assignment requests:</h3>
+<ul>
+    {% for assignment in object.editorial_assignments.all %}
+        {% include 'partials/submissions/pool/assignment_info.html' with assignment=assignment %}
+    {% empty %}
+        <li>No assignment requests have been sent</li>
+    {% endfor %}
+</ul>
diff --git a/submissions/templates/partials/submissions/arxiv_queryresult.html b/submissions/templates/partials/submissions/arxiv_queryresult.html
index 5f2ad667f742f9c0ea66a2915602b3fde1172c26..e469a0320a9387051903a8d4dbccebba92d00d64 100644
--- a/submissions/templates/partials/submissions/arxiv_queryresult.html
+++ b/submissions/templates/partials/submissions/arxiv_queryresult.html
@@ -1,10 +1,12 @@
 <div class="card-body">
     <h3 class="card-title">{{ item.title }}</h3>
     <div class="card-text">
-        {% for author in item.authors %}
-            {{ author.name }}{% if not forloop.last %},{% endif %}
-        {% endfor %}
-        - <a href="{{ item.id }}" target="_blank">{{ item.id }}</a>
+        <a href="javascript:;" data-toggle="toggle" data-target="#arxiv_authors_{{ id }}_{{ id2 }}">Toggle authors</a> &middot; <a href="{{ item.link }}" target="_blank">{{ item.id }}</a>
+        <div class="authors mt-2" id="arxiv_authors_{{ id }}_{{ id2 }}" style="display: none;">
+            {% for author in item.authors %}
+                {{ author.name }}{% if not forloop.last %},{% endif %}
+            {% endfor %}
+        </div>
     </div>
     <p class="card-text text-muted">Published: {{ item.published }}</p>
 </div>
diff --git a/submissions/templates/submissions/admin/editorial_assignment_failed.html b/submissions/templates/submissions/admin/editorial_assignment_failed.html
deleted file mode 100644
index cd2931bea482477f5fd6ce8777d9a2cb50db2a52..0000000000000000000000000000000000000000
--- a/submissions/templates/submissions/admin/editorial_assignment_failed.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% extends 'scipost/base.html' %}
-
-{% load bootstrap %}
-
-{% block pagetitle %}: assignment failed (ack){% endblock pagetitle %}
-
-{% block content %}
-
-<h1>Assignment has failed for Submission</h1>
-<p>{{ submission.title }} by {{ submission.author_list }}.</p>
-<p>Please add comments on the Submission in this box.</p>
-<form action="{% url 'submissions:assignment_failed' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr %}" method="POST">
-    {% csrf_token %}
-    {{ form|bootstrap }}
-    <input type="submit" name="Submit" class="btn btn-primary" />
-</form>
-
-{% endblock content %}
diff --git a/submissions/templates/submissions/admin/editorial_assignment_form.html b/submissions/templates/submissions/admin/editorial_assignment_form.html
index df473a80d47ac289a9f7303c1965dff8c4344d05..a437401f49b0a43daad1775e9280f065fb82cef9 100644
--- a/submissions/templates/submissions/admin/editorial_assignment_form.html
+++ b/submissions/templates/submissions/admin/editorial_assignment_form.html
@@ -62,4 +62,38 @@
     </div>
 </div>
 
+
+<div class="row">
+    <div class="col-12">
+        {% if coauthorships %}
+            <div class="card border-danger">
+                <div class="card-body">
+                    <h3 class="card-title text-danger">The system identified the following potential coauthorships (from arXiv database)</h3>
+                    <p class="card-text text-danger">(only up to 5 most recent shown; if within the last 3 years, referee is disqualified):</p>
+                </div>
+                <div class="card-body">
+                    <ul class="list-group list-group-flush">
+                        {% for author, entries in coauthorships.items %}
+                            <li class="list-group-item pt-3">
+                                <div class="card-content">
+                                    <h3>For Fellow: {{ author }}</h3>
+                                </div>{{ value}}
+                            </li>
+                            {% for entry in entries %}
+                                <li class="list-group-item">
+                                    {% include 'partials/submissions/arxiv_queryresult.html' with item=entry id=forloop.counter id2=forloop.parentloop.counter %}
+                                </li>
+                            {% endfor %}
+                        {% endfor %}
+                    </ul>
+                </div>
+            </div>
+        {% else %}
+            <h3 class="text-success">The system has not identified any coauthorships (from arXiv database)</h3>
+        {% endif %}
+    </div>
+</div>
+
+
+
 {% endblock %}
diff --git a/submissions/templates/submissions/admin/recommendation_prepare_for_voting.html b/submissions/templates/submissions/admin/recommendation_prepare_for_voting.html
index 67c157592a55c34617d064ac1bcb1f052b409060..b7ff99ca46377deb652e6f999885ea51cf5e2f5a 100644
--- a/submissions/templates/submissions/admin/recommendation_prepare_for_voting.html
+++ b/submissions/templates/submissions/admin/recommendation_prepare_for_voting.html
@@ -49,22 +49,22 @@
 <div class="row">
     <div class="col-12">
         {% if coauthorships %}
-            <div class="card card-outline-danger">
+            <div class="card border-danger">
                 <div class="card-body">
                     <h3 class="card-title text-danger">The system identified the following potential coauthorships (from arXiv database)</h3>
                     <p class="card-text text-danger">(only up to 5 most recent shown; if within the last 3 years, referee is disqualified):</p>
                 </div>
                 <div class="card-body">
                     <ul class="list-group list-group-flush">
-                        {% for key, value in coauthorships.items %}
+                        {% for author, entries in coauthorships.items %}
                             <li class="list-group-item pt-3">
                                 <div class="card-content">
-                                    <h3>For Fellow {{key}}:</h3>
+                                    <h3>For Fellow: {{ author }}</h3>
                                 </div>
                             </li>
-                            {% for entry in value.entries %}
+                            {% for entry in entries %}
                                 <li class="list-group-item">
-                                    {% include 'partials/submissions/arxiv_queryresult.html' with item=entry %}
+                                    {% include 'partials/submissions/arxiv_queryresult.html' with item=entry id=forloop.counter id2=forloop.parentloop.counter %}
                                 </li>
                             {% endfor %}
                         {% endfor %}
diff --git a/submissions/templates/submissions/referee_form.html b/submissions/templates/submissions/referee_form.html
index 8fae92385d4bde0416a0f6bffbb356bec371811f..9935f079af18f9a31efc4747dceeb75c49d1f2e9 100644
--- a/submissions/templates/submissions/referee_form.html
+++ b/submissions/templates/submissions/referee_form.html
@@ -52,16 +52,16 @@
 {% if queryresults.entries %}
 <div class="row">
     <div class="col-12">
-        <div class="card card-outline-danger">
+        <div class="card border-danger">
             <div class="card-body">
                 <h3 class="card-title text-danger">The system identified the following potential coauthorships (from arXiv database)</h3>
                 <p class="card-text text-danger">(only up to 5 most recent shown; if within the last 3 years, referee is disqualified):</p>
             </div>
             <div class="card-body">
-                <ul class="list-group list-group-flush">
+                <ul class="list-group list-group-flush px-0">
                     {% for entry in queryresults.entries %}
                         <li class="list-group-item">
-                            {% include 'partials/submissions/arxiv_queryresult.html' with item=entry %}
+                            {% include 'partials/submissions/arxiv_queryresult.html' with item=entry id=forloop.counter id2=0 %}
                         </li>
                     {% endfor %}
                 </ul>
diff --git a/submissions/utils.py b/submissions/utils.py
index 44115064ba9bfc12aced5a0b3e6d217b9f1b7404..5098fbc6b3e7dc5dad7a6b5315bd1bcf9439b55e 100644
--- a/submissions/utils.py
+++ b/submissions/utils.py
@@ -569,68 +569,6 @@ class SubmissionUtils(BaseMailUtil):
         emailmessage.attach_alternative(html_version, 'text/html')
         emailmessage.send(fail_silently=False)
 
-    @classmethod
-    def assignment_failed_email_authors(cls):
-        """ Requires loading 'submission' attribute. """
-        email_text = ('Dear ' + cls.submission.submitted_by.get_title_display() + ' '
-                      + cls.submission.submitted_by.user.last_name
-                      + ', \n\nYour recent Submission to SciPost,\n\n'
-                      + cls.submission.title + ' by ' + cls.submission.author_list
-                      + '\n\nhas unfortunately not passed the pre-screening stage. '
-                      'We therefore regret to inform you that we will not '
-                      'process your paper further towards publication, and that you '
-                      'are now free to send your manuscript to an alternative journal.')
-        if len(cls.personal_message) > 3:
-            email_text += '\n\n' + cls.personal_message
-        email_text += ('\n\nWe nonetheless thank you very much for your contribution.'
-                       '\n\nSincerely,' +
-                       '\n\nThe SciPost Team.')
-        email_text_html = (
-            '<p>Dear {{ title }} {{ last_name }},</p>'
-            '<p>Your recent Submission to SciPost,</p>'
-            '<p>{{ sub_title }}</p>'
-            '\n<p>by {{ author_list }}</p>'
-            '\n<p>has unfortunately not passed the pre-screening stage. '
-            'We therefore regret to inform you that we will not '
-            'process your paper further towards publication, and that you '
-            'are now free to send your manuscript to an alternative journal.</p>')
-        if len(cls.personal_message) > 3:
-            email_text_html += '{{ personal_message|linebreaks }}'
-        email_text_html += (
-            '<p>We nonetheless thank you very much for your contribution.</p>'
-            '<p>Sincerely,</p>'
-            '<p>The SciPost Team.</p>')
-        email_context = {
-            'title': cls.submission.submitted_by.get_title_display(),
-            'last_name': cls.submission.submitted_by.user.last_name,
-            'sub_title': cls.submission.title,
-            'author_list': cls.submission.author_list,
-            'personal_message': cls.personal_message,
-        }
-        email_text_html += '<br/>' + EMAIL_FOOTER
-        html_template = Template(email_text_html)
-        html_version = html_template.render(Context(email_context))
-        emailmessage = EmailMultiAlternatives(
-            'SciPost: pre-screening not passed', email_text,
-            'SciPost Editorial Admin <submissions@scipost.org>',
-            [cls.submission.submitted_by.user.email],
-            bcc=['submissions@scipost.org'],
-            reply_to=['submissions@scipost.org'])
-        emailmessage.attach_alternative(html_version, 'text/html')
-        emailmessage.send(fail_silently=False)
-
-    @classmethod
-    def send_refereeing_invitation_email(cls):
-        """
-        This method is called by send_refereeing_invitation in submissions/views.
-        It is used when the referee is already a registered contributor.
-        If a referee is not yet registered, the method recruit_referee is used
-        instead, which calls the send_registration_email method in scipost/utils.
-        Requires loading 'invitation' attribute.
-        """
-        raise DeprecationWarning(('Use new mails.views.MailEditingSubView() with code'
-                                  ' `submission_referee_invite` instead'))
-
     @classmethod
     def send_unreg_ref_reminder_email(cls):
         """
diff --git a/submissions/views.py b/submissions/views.py
index 30a3e980fcb3a8d4555bc4c3f1ab35ada22b6882..3c1c2e08f13e5656a35d70ce0adb45d460857489 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -1,4 +1,4 @@
-__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)"
+ip__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
@@ -25,7 +25,7 @@ from django.views.generic.list import ListView
 from guardian.shortcuts import assign_perm
 
 from .constants import STATUS_VETTED, STATUS_EIC_ASSIGNED,\
-                       SUBMISSION_STATUS_PUBLICLY_INVISIBLE, SUBMISSION_STATUS,\
+                       SUBMISSION_STATUS_PUBLICLY_INVISIBLE, SUBMISSION_STATUS, STATUS_ASSIGNMENT_FAILED,\
                        STATUS_DRAFT, CYCLE_DIRECT_REC, STATUS_VOTING_IN_PREPARATION,\
                        STATUS_PUT_TO_EC_VOTING
 from .models import Submission, EICRecommendation, EditorialAssignment,\
@@ -43,8 +43,6 @@ from .utils import SubmissionUtils
 
 from colleges.permissions import fellowship_required, fellowship_or_admin_required
 from comments.forms import CommentForm
-from invitations.constants import INVITATION_REFEREEING
-from invitations.models import RegistrationInvitation
 from journals.models import Journal
 from mails.views import MailEditingSubView
 from production.forms import ProofsDecisionForm
@@ -451,8 +449,13 @@ def assign_submission(request, arxiv_identifier_w_vn_nr):
         SubmissionUtils.send_assignment_request_email()
         messages.success(request, 'Your assignment request has been sent successfully.')
         return redirect('submissions:pool')
+
+    fellows_with_expertise = submission.fellows.all()
+    coauthorships = submission.flag_coauthorships_arxiv(fellows_with_expertise)
+
     context = {
         'submission_to_assign': submission,
+        'coauthorships': coauthorships,
         'form': form
     }
     return render(request, 'submissions/admin/editorial_assignment_form.html', context)
@@ -571,14 +574,18 @@ def volunteer_as_EIC(request, arxiv_identifier_w_vn_nr):
         deadline += datetime.timedelta(days=28)
 
     # Update Submission data
-    submission.status = STATUS_EIC_ASSIGNED
-    submission.editor_in_charge = contributor
-    submission.open_for_reporting = True
-    submission.reporting_deadline = deadline
-    submission.open_for_commenting = True
-    submission.save()
-    submission.touch()
-
+    Submission.objects.filter(id=submission.id).update(
+        status=STATUS_EIC_ASSIGNED,
+        editor_in_charge=contributor,
+        open_for_reporting=True,
+        reporting_deadline=deadline,
+        open_for_commenting=True,
+        latest_activity=timezone.now())
+
+    # Deprecate old Editorial Assignments
+    EditorialAssignment.objects.filter(submission=submission).open().update(deprecated=True)
+
+    # Send emails to EIC and authors regarding the EIC assignment.
     SubmissionUtils.load({'assignment': assignment})
     SubmissionUtils.deprecate_other_assignments()
     SubmissionUtils.send_EIC_appointment_email()
@@ -596,41 +603,40 @@ def volunteer_as_EIC(request, arxiv_identifier_w_vn_nr):
 @permission_required('scipost.can_assign_submissions', raise_exception=True)
 @transaction.atomic
 def assignment_failed(request, arxiv_identifier_w_vn_nr):
+    """Reject a Submission in pre-screening.
+
+    No Editorial Fellow has accepted or volunteered to become Editor-in-charge., hence the
+    Submission is rejected. An Editorial Administrator can access this view from the Pool.
     """
-    No Editorial Fellow has accepted or volunteered to become Editor-in-charge.
-    The submission is rejected.
-    This method is called from pool.html by an Editorial Administrator.
-    """
-    submission = get_object_or_404(Submission.objects.pool(request.user),
+    submission = get_object_or_404(Submission.objects.pool(request.user).prescreening(),
                                    arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr)
-    if request.method == 'POST':
-        form = ModifyPersonalMessageForm(request.POST)
-        if form.is_valid():
-            submission.status = 'assignment_failed'
-            submission.latest_activity = timezone.now()
-            submission.save()
-            SubmissionUtils.load({'submission': submission,
-                                  'personal_message': form.cleaned_data['personal_message']})
-            SubmissionUtils.deprecate_all_assignments()
-            SubmissionUtils.assignment_failed_email_authors()
-            context = {'ack_header': ('Submission ' + submission.arxiv_identifier_w_vn_nr +
-                                      ' has failed pre-screening and been rejected. '
-                                      'Authors have been informed by email.'),
-                       'followup_message': 'Return to the ',
-                       'followup_link': reverse('submissions:pool'),
-                       'followup_link_label': 'Submissions pool'}
-            return render(request, 'scipost/acknowledgement.html', context)
+
+    mail_request = MailEditingSubView(
+        request, mail_code='submissions_assignment_failed', instance=submission,
+        header_template='partials/submissions/admin/editorial_assignment_failed.html')
+    if mail_request.is_valid():
+        # Deprecate old Editorial Assignments
+        EditorialAssignment.objects.filter(submission=submission).open().update(deprecated=True)
+
+        # Update status of Submission
+        submission.touch()
+        Submission.objects.filter(id=submission.id).update(status=STATUS_ASSIGNMENT_FAILED)
+
+        messages.success(
+            request, 'Submission {arxiv} has failed pre-screening and been rejected.'.format(
+                arxiv=submission.arxiv_identifier_w_vn_nr))
+        messages.success(request, 'Authors have been informed by email.')
+        mail_request.send()
+        return redirect(reverse('submissions:pool'))
     else:
-        form = ModifyPersonalMessageForm()
-    context = {'submission': submission,
-               'form': form}
-    return render(request, 'submissions/admin/editorial_assignment_failed.html', context)
+        return mail_request.return_render()
 
 
 @login_required
 @fellowship_required()
 def assignments(request):
-    """
+    """List editorial tasks for a Fellow.
+
     This page provides a Fellow with an explicit task list
     of editorial actions which should be undertaken.
     """
@@ -651,10 +657,10 @@ def assignments(request):
 @login_required
 @fellowship_or_admin_required()
 def editorial_page(request, arxiv_identifier_w_vn_nr):
-    """
-    The central page for the EIC to manage all its Editorial duties.
+    """Detail page of a Submission its editorial tasks.
 
-    Accessible for: Editor-in-charge and Editorial Administration
+    The central page for the Editor-in-charge to manage all its Editorial duties. It's accessible
+    for both the Editor-in-charge of the Submission and the Editorial Administration.
     """
     submission = get_object_or_404(Submission.objects.pool_full(request.user),
                                    arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr)
@@ -736,7 +742,7 @@ def select_referee(request, arxiv_identifier_w_vn_nr):
                 sub_auth_boolean_str += '+OR+' + author['name'].split()[-1]
             sub_auth_boolean_str += ')+AND+'
             search_str = sub_auth_boolean_str + ref_search_form.cleaned_data['last_name'] + ')'
-            queryurl = ('http://export.arxiv.org/api/query?search_query=au:%s'
+            queryurl = ('https://export.arxiv.org/api/query?search_query=au:%s'
                         % search_str + '&sortBy=submittedDate&sortOrder=descending'
                         '&max_results=5')
             arxivquery = feedparser.parse(queryurl)
@@ -1389,11 +1395,6 @@ def prepare_for_voting(request, rec_id):
     recommendation = get_object_or_404(
         EICRecommendation.objects.active().filter(submission__in=submissions), id=rec_id)
 
-    fellows_with_expertise = recommendation.submission.fellows.filter(
-        contributor__expertises__contains=[recommendation.submission.subject_area])
-
-    coauthorships = {}
-
     eligibility_form = VotingEligibilityForm(request.POST or None, instance=recommendation)
     if eligibility_form.is_valid():
         eligibility_form.save()
@@ -1406,23 +1407,9 @@ def prepare_for_voting(request, rec_id):
         return redirect(reverse('submissions:editorial_page',
                                 args=[recommendation.submission.arxiv_identifier_w_vn_nr]))
     else:
-        # Identify possible co-authorships in last 3 years, disqualifying Fellow from voting:
-        if recommendation.submission.metadata is not None:
-            for fellow in fellows_with_expertise:
-                sub_auth_boolean_str = '((' + (recommendation.submission
-                                               .metadata['entries'][0]['authors'][0]['name']
-                                               .split()[-1])
-                for author in recommendation.submission.metadata['entries'][0]['authors'][1:]:
-                    sub_auth_boolean_str += '+OR+' + author['name'].split()[-1]
-                    sub_auth_boolean_str += ')+AND+'
-                    search_str = sub_auth_boolean_str + fellow.contributor.user.last_name + ')'
-                    queryurl = ('http://export.arxiv.org/api/query?search_query=au:%s'
-                                % search_str + '&sortBy=submittedDate&sortOrder=descending'
-                                '&max_results=5')
-                    arxivquery = feedparser.parse(queryurl)
-                    queryresults = arxivquery
-                    if queryresults.entries:
-                        coauthorships[fellow.contributor.user.last_name] = queryresults
+        fellows_with_expertise = recommendation.submission.fellows.filter(
+            contributor__expertises__contains=[recommendation.submission.subject_area])
+        coauthorships = recommendation.submission.flag_coauthorships_arxiv(fellows_with_expertise)
 
     context = {
         'recommendation': recommendation,
diff --git a/templates/search/indexes/comments/comment_text.txt b/templates/search/indexes/comments/comment_text.txt
index e187fa7fe26f1fc628c3190ea008c6eeec87dc31..896dec580c8f2d3fb36fbbbf840076ce88922a09 100644
--- a/templates/search/indexes/comments/comment_text.txt
+++ b/templates/search/indexes/comments/comment_text.txt
@@ -1,3 +1,3 @@
 {{object.comment_text}}
 {{object.date_submitted}}
-{{object.author}}
+{% if not object.anonymous %}{{ object.author }}{% endif %}